diff --git a/bin/tsvhead b/bin/tsvhead
new file mode 120000
index 0000000..2d36d85
--- /dev/null
+++ b/bin/tsvhead
@@ -0,0 +1 @@
+../tsv/tsvhead
\ No newline at end of file
diff --git a/bin/tsvtail b/bin/tsvtail
new file mode 120000
index 0000000..ae31ea4
--- /dev/null
+++ b/bin/tsvtail
@@ -0,0 +1 @@
+../tsv/tsvtail
\ No newline at end of file
diff --git a/tsv/tsvhead b/tsv/tsvhead
new file mode 100755
index 0000000..c40df35
--- /dev/null
+++ b/tsv/tsvhead
@@ -0,0 +1,90 @@
+#!/usr/bin/env python
+#
+# Copyright 2015 Ville Rantanen
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see .
+#
+
+'''simple head for tsv/csv files.'''
+
+__author__ = "Ville Rantanen "
+
+__version__ = "0.1"
+
+import sys,os,argparse
+from argparse import ArgumentParser
+
+def setup_options():
+ ''' Create command line options '''
+ usage='''
+Simple implementation of head that keeps the header row.
+
+'''
+
+ parser=ArgumentParser(description=usage,
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ epilog="\n".join(["Version: "+__version__,__author__]))
+ common_group=parser.add_argument_group('common', 'Common options')
+ common_group.add_argument("-v","--version",action="version",version=__version__)
+ common_group.add_argument("-n",type=int,dest="lines",default=False,
+ help="Lines to show from beginning of file. Negative value to show lines but the number. Default: 10")
+ parser.add_argument("file",type=str, nargs='*',
+ help="File(s) to be headed")
+ opts=parser.parse_args()
+ if not opts.lines:
+ int(opts.file[0])
+ opts.lines=int(opts.file.pop(0))
+ if not opts.lines:
+ opts.lines=10
+ return opts
+
+def behead(fileob,opts):
+
+ header=fileob.readline()
+ sys.stdout.write(header)
+ if opts.lines>=0:
+ head_ordinary(fileob, opts.lines)
+ else:
+ head_allbutlast(fileob, opts.lines)
+
+def head_ordinary(fileob, lines):
+ for i,row in enumerate(fileob):
+ if i>lines-1:
+ break
+ sys.stdout.write(row)
+
+def head_allbutlast(fileob, lines):
+ lines=-lines
+ buf=[]
+ for row in fileob:
+ buf.append(row)
+ if len(buf)>lines:
+ sys.stdout.write(buf.pop(0))
+
+def main():
+ opts=setup_options()
+ try:
+ if (not sys.stdin.isatty()):
+ behead(sys.stdin, opts)
+ for fi in opts.file:
+ behead(open(fi,'r'), opts)
+ except IOError as (n,e):
+ if n==32:
+ pass
+ else:
+ import traceback
+ print traceback.format_exc()
+
+if __name__ == "__main__":
+ main()
diff --git a/tsv/tsvtail b/tsv/tsvtail
new file mode 100755
index 0000000..7c2f478
--- /dev/null
+++ b/tsv/tsvtail
@@ -0,0 +1,94 @@
+#!/usr/bin/env python
+#
+# Copyright 2015 Ville Rantanen
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see .
+#
+
+'''simple tail for tsv/csv files.'''
+
+__author__ = "Ville Rantanen "
+
+__version__ = "0.1"
+
+import sys,os,argparse
+from argparse import ArgumentParser
+
+def setup_options():
+ ''' Create command line options '''
+ usage='''
+simple implementation of tail, keeping the header row
+
+'''
+
+ parser=ArgumentParser(description=usage,
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ epilog="\n".join(["Version: "+__version__,__author__]))
+ common_group=parser.add_argument_group('common', 'Common options')
+ common_group.add_argument("-v","--version",action="version",version=__version__)
+ common_group.add_argument("-n",type=str,dest="lines",default=False,
+ help="Lines to show from end of file. +K to start output from the Kth. Default: 10")
+ parser.add_argument("file",type=str, nargs='*',
+ help="File(s) to be headed")
+ opts=parser.parse_args()
+ if not opts.lines:
+ int(opts.file[0])
+ opts.lines=opts.file.pop(0)
+ if not opts.lines:
+ opts.lines="10"
+ if opts.lines.startswith("+"):
+ opts.lines=-int(opts.lines)
+ else:
+ opts.lines=int(opts.lines)
+ return opts
+
+def tail(fileob,opts):
+
+ header=fileob.readline()
+ sys.stdout.write(header)
+ if opts.lines>=0:
+ tail_ordinary(fileob, opts.lines)
+ else:
+ tail_allbutfirst(fileob, -opts.lines)
+
+def tail_allbutfirst(fileob, lines):
+ for i,row in enumerate(fileob):
+ if ilines:
+ buf.pop(0)
+ [sys.stdout.write(l) for l in buf]
+
+def main():
+ opts=setup_options()
+ try:
+ if (not sys.stdin.isatty()):
+ tail(sys.stdin, opts)
+ for fi in opts.file:
+ tail(open(fi,'r'), opts)
+ except IOError as (n,e):
+ if n==32:
+ pass
+ else:
+ import traceback
+ print traceback.format_exc()
+
+if __name__ == "__main__":
+ main()