1. Overview
In this tutorial, we’ll see what the “-” character is about and what purpose it serves. We’ll take a look at the most common use-cases where the use of “-” makes more sense than alternative approaches.
2. The Meaning of “-” Character
The “-” character means different things to different commands on the Linux terminal. There is no universal convention for using the “-” character with the Linux commands. However, on the most commonly used shells like bash and zsh, the “-” character is used to specify a standard input or a standard output for a command. It’s a command-specific convention for many Linux utilities.
On the other hand, other tools or commands on Linux might have a different use-case for the “-” character. For instance, we use the “-” with the git command to specify a repository branch. For other tools that expect a file as an input, like tar, the “-” character is used to treat the output of another command as the contents of an input file. Hence, we do not need to specify a file path to the command.
3. Using “-” to Specify a Standard Input
Most of the commands on Linux treat the string “-” as a synonym for stdin or stdout. So, for instance, when we use the cat command with a naked “-“, it will read from stdin:
$ cat -
I am being echoed.
I am being echoed.
The “-” in the above command is actually an alias for /dev/stdin. Therefore, we can also replace the “-” with /dev/stdin, and nothing will change:
$ cat /dev/stdin
Echo this.
Echo this.
So, it begs the question, what is /dev/stdin? Well, /dev/stdin is a symbolic link to /proc/self/fd/0. The /proc/self/fd/0, in turn, is a symbolic link to the standard input of our current shell process, which is our terminal. For that reason, we’re able to input text to the cat command using our terminal.
Similarly, we can use the tar command to extract a tarball and print it to stdout. The contents of the tarball printed to stdout will act as input to the tar command, which will untar the contents and write them to the disk as shown in the following snippet:
$ <htop-2.2.0.tar.gz | tar -xzf -
Let’s break it down:
- We print the contents of the htop-2.2.0.tar.gz archive to stdout using the redirect operator <
- Then we pipe the command to tar, which reads the contents of the htop-2.2.0.tar.gz from stdout
- The -x option extracts the file, or the contents of stdout in this case
- The -z option filters the contents through gzip
- The -f option writes the extracted contents to a file or directory
Another practical use-case of using tar with “-” is when we want to download a remote file and extract it once it is downloaded. We can use curl to print the text or binary output of the downloaded file to the stdout. Then, we can pipe whatever is printed to the stdout to tar and specify the contents of the stdout as stdin:
$ curl -L https://github.com/hishamhm/htop/archive/refs/tags/2.2.0.tar.gz --output - | tar zxf -
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 130 100 130 0 0 135 0 --:--:-- --:--:-- --:--:-- 135
100 168k 0 168k 0 0 77436 0 --:--:-- 0:00:02 --:--:-- 309k
$ ls -lF
drwxr-xr-x hey hey 4.0 KB Wed Dec 1 22:41:43 2021 htop-2.2.0/
4. Using “-” to Specify a Standard Output
In the same way, we can also use “-” to specify a standard output for a specific command. In our curl example, we used “-” to print the binary output of the remote file to our standard output:
$ curl -L https://github.com/hishamhm/htop/archive/refs/tags/2.2.0.tar.gz --output -
E�P��7�&�3Dq�"!GKvL�[f>��GY6as<Hl�'�)2'AS�*��~맊VT#a;�}x܍ҋ�zN
�8YWslw>���bmLf-~r+�����ju��WTr
��υ<��u�kIM�wyfٚ9~a9
...
As we can see, we explicitly told the curl command to output the contents of the binary file because, by default, curl will not print binary contents to stdout. Like stdin, when “-” is used in the context of stdout, it’s an alias for /dev/stdout.
So, one might wonder why we print the binary output to our standard output. Well, we can do a lot of useful tasks with it. In our next example, we’ll write a command that basically downloads a picture using curl and then creates a favicon out of the image using ImageMagick. Once the image is resized, we’ll convert it to base64 and POST the result to an endpoint. We’ll do all these tasks only by reading and writing to stdin and stdout, without having to save the contents in a file on the disk:
$ curl https://upload.wikimedia.org/wikipedia/commons/4/45/Linux-for-workgroups-boot.jpg --output - \
| convert - -resize 16x16 png:- \
| base64\
| curl -X POST --data @- -H 'Content-Type: text/plain' https://example.com/favicon
Let’s break it down:
- In our first command, we download a picture and print its binary contents to stdout using the –output – option
- Next up, we pipe the contents to the convert command, which reads from the stdout and resizes the image
- When the image is resized, the PNG contents of the resized image is printed out to stdout as indicated by png:-
- Afterward, the contents are piped to the base64 command, which prints out the base64 contents of the resized favicon
- Finally, curl makes a post request to our example endpoint with the data picked from the standard output as signified by the –data @- option
As we can see, we used the “-” for both stdin and stdout. It’s up to the command itself to interpret it accordingly. Of course, we can replace “-” with /dev/stdin and /dev/stdout, and the result will be the same.
5. Using “-” for Git Branches
As we know, the “-” means different things to different commands. In the case of git, we can use it as an argument to the git checkout command to check out the previous active branch or detached HEAD. For instance, if we have a Git repository and two branches on the repository, we can switch between those two branches by using “-“:
$ git branch -a
*master
dev
$ git checkout dev
$ git branch -a
master
*dev
$ git checkout -
$ git branch -a
*master
dev
6. Using “-” With the cd Command
Similarly, as with the git command, we can also use “-” as an argument to the cd command to switch between the current and the previous directory.
Let’s see it in action:
$ pwd
/home/hey/github
$ cd TestApp
$ pwd
/home/hey/github/TestApp
$ cd -
$ pwd
/home/hey/github
$ cd -
$ pwd
/home/hey/github/TestApp
Our shell stores the old path in an environment variable known as $OLDPWD. Therefore, the “-” parameter acts as an alias for $OLDPWD:
$ echo $OLDPWD
/home/hey/github/TestApp
$ cd $OLDPWD
$ pwd
/home/hey/github/TestApp
$ echo $OLDPWD
/home/hey/github
7. Where Else Can We Use “-“?
As we saw, it’s up to each tool or command to interpret the “-” parameter. However, many other tools use the “-” parameter for different purposes. The most common and reliable way to find out whether a tool has support for the “-” parameter is to go through its official manpages.
8. Conclusion
In this article, we looked at the meaning of using “-” in the Linux command-line and how it is interpreted by the most common commands. We also saw a few use cases where we can use “-” to read from stdin and write to stdout.
Finally, we saw how to use “-” with git and cd commands.