Implementing the "head" Unix command
Have I mentioned how much I love John Crickett’s coding challenges? In this post, I cover the completion of my 2nd coding challenge, an implementation (in Python) of the unix/Unix command-line tool head
.
About
py-head
is a minimal implementation of the Unix-style command-line tool named head
. It is a command-line tool that displays the first n
lines or c
bytes of a file, where the user can provide the value for n
and c
. If no file or value for n
or c
is provided, then it displays the first 10 lines from the standard input.
Similar to my py-wc
project, I decided to code this up in Python since that’s the language I’m most familiar with. This allowed me to focus more on the workflow of head
and less on the syntax of the language I was working with.
Instructions
To use this as a command-line tool, I recommend adding the finished script to PATH / system variables. For Windows, create a folder named Aliases
in your C drive: C:/Aliases
, and then add this folder to PATH. Next, create a batch file that will execute when you call the specified alias. For example, on my machine, I have a batch file named head.bat
located at C:/Aliases
, that contains the following script:
1
2
3
@echo off
echo.
python C:\...\GitHub\py-head\main.py %*
So now, when I type head
in the command prompt, this batch file will execute, which in turn, runs the py-head
Python script.
Examples
py-head
allows you to execute typical Unix-style head
commands. If no flags are included with the filename, it prints the entire file contents:
C:\> head hello.txt
hello, world!
C:\> head small.txt
The Project Gutenberg eBook of The Art of War
This ebook is for the use of anyone anywhere in the United States and
most other parts of the world at no cost and with almost no restrictions
whatsoever. You may copy it, give it away or re-use it under the terms
of the Project Gutenberg License included with this ebook or online
at www.gutenberg.org. If you are not located in the United States,
you will have to check the laws of the country where you are located
before using this eBook.
If no file is included, it displays the first 10 lines from standard input:
C:\> head
Some text that I entered
Some text that I entered
line 2
line 2
line 3
line 3
this is line 4
this is line 4
now this is line 5
now this is line 5
hello
hello
world
world
this is line 8
this is line 8
line 9
line 9
10!
10!
We can also specify and display only the first n
lines (note that you can list the flag in any order):
C:\> head small.txt -n3
The Project Gutenberg eBook of The Art of War
This ebook is for the use of anyone anywhere in the United States and
C:\> head small.txt -n 3
The Project Gutenberg eBook of The Art of War
This ebook is for the use of anyone anywhere in the United States and
C:\> head -n3 small.txt
The Project Gutenberg eBook of The Art of War
This ebook is for the use of anyone anywhere in the United States and
C:\> head -n 3 small.txt
The Project Gutenberg eBook of The Art of War
This ebook is for the use of anyone anywhere in the United States and
And we can also specify and display only the first c
bytes:
C:\> head large.txt -c243
The Project Gutenberg eBook of The Art of War
This ebook is for the use of anyone anywhere in the United States and
most other parts of the world at no cost and with almost no restrictions
whatsoever. You may copy it, give it away or
C:\> head large.txt -c 42
The Project Gutenberg eBook of The Art of
We can also pass in multiple files
C:\> head hello.txt small.txt hello.txt
==> hello.txt <==
hello, world!
==> small.txt <==
The Project Gutenberg eBook of The Art of War
This ebook is for the use of anyone anywhere in the United States and
most other parts of the world at no cost and with almost no restrictions
whatsoever. You may copy it, give it away or re-use it under the terms
of the Project Gutenberg License included with this ebook or online
at www.gutenberg.org. If you are not located in the United States,
you will have to check the laws of the country where you are located
before using this eBook.
==> hello.txt <==
hello, world!
C:\> head hello.txt hello.txt hello.txt hello.txt
==> hello.txt <==
hello, world!
==> hello.txt <==
hello, world!
==> hello.txt <==
hello, world!
==> hello.txt <==
hello, world!
And finally, we can pass in multiple files, along with the n
or c
flag:
C:\> head hello.txt hello.txt hello.txt hello.txt -c9
==> hello.txt <==
hello, wo
==> hello.txt <==
hello, wo
==> hello.txt <==
hello, wo
==> hello.txt <==
hello, wo
C:\> head large.txt small.txt hello.txt -n 7
==> large.txt <==
The Project Gutenberg eBook of The Art of War
This ebook is for the use of anyone anywhere in the United States and
most other parts of the world at no cost and with almost no restrictions
whatsoever. You may copy it, give it away or re-use it under the terms
of the Project Gutenberg License included with this ebook or online
at www.gutenberg.org. If you are not located in the United States,
==> small.txt <==
The Project Gutenberg eBook of The Art of War
This ebook is for the use of anyone anywhere in the United States and
most other parts of the world at no cost and with almost no restrictions
whatsoever. You may copy it, give it away or re-use it under the terms
of the Project Gutenberg License included with this ebook or online
at www.gutenberg.org. If you are not located in the United States,
==> hello.txt <==
hello, world!
Libraries
Just like the py-wc
project, everything I needed for py-head
was included in Python’s Standard Library. Some basic I/O with Python’s built-in open
function, command-line parsing with the argparse
library, and some directory navigation with os
.
If you’ve never used argparse
, I highly recommend it for handling parsing of command-line inputs for programs, here’s an example from my repo for this project:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
if __name__ == '__main__':
# Create an ArgumentParser object
parser = argparse.ArgumentParser(description='Process text file(s).')
# Add arguments for input file(s)
parser.add_argument(
'input_files',
nargs='*', # 0 or more input files
type=str,
default=[],
help='Path to the input file(s). Pass no options with input file to print out the contents of the entire file. Pass no file to read from user input.'
)
# Create a mutually exclusive group for -c and -n flags
group = parser.add_mutually_exclusive_group()
# Add flags for different options to the mutually exclusive group created above
group.add_argument('-c', '--bytes', type=int, default=None, help='Print bytes')
group.add_argument('-n', '--lines', type=int, default=None, help='Print lines')
# Parse the command-line arguments
args = parser.parse_args()
# more code below...
The full code for this project can be found at my Github here.
Acknowledgements
Thanks to John Crickett for the idea from his site, Coding Challenges!
Text samples were downloaded from this site.
If you happen to peruse my code and notice any bugs or opportunities for optimizations, please let me know!