111

Given the following command:

gzip -dc /cdrom/cdrom0/file.tar.gz | tar xvf –

What does the - at the end of the command mean? Is it some kind of placeholder?

bahamat
  • 38,658
  • 4
  • 70
  • 103
Eugene S
  • 3,444
  • 8
  • 29
  • 35
  • 6
    One small detail to mention: the `-` not needs to be at the end of the command. For example: `ls -l | diff - /old_ls_output.txt`. – manatwork Jul 02 '12 at 06:10

2 Answers2

115

In this case, it means ‘standard input’. It's used by some software (e.g. tar) when a file argument is required and you need to use stdin instead. It's not a shell construct and it depends on the program you're using. Check the manpage if in doubt!

In this instance, standard input is the argument to the -f option. In cases where - isn't supported, you can get away with using something like tar xvf /proc/self/fd/0 or tar xvf /dev/stdin (the latter is widely supported in various unices).

Don't rely on this to mean ‘standard input’ universally. Since it's not interpreted by the shell, every program is free to deal with it as it pleases. In some cases, it's standard output or something entirely different: on su it signifies ‘start a login shell’. In other cases, it's not interpreted at all. Muscle memory has made me create quite a few files named - because some version of some program I was used to didn't understand the dash.

Kusalananda
  • 320,670
  • 36
  • 633
  • 936
Alexios
  • 18,757
  • 3
  • 57
  • 74
  • 8
    It can also mean `STDOUT`, depending on the context. – bahamat Jun 28 '12 at 10:32
  • 3
    And pretty much anything else, as it's up to individual programs to interpret. – Alexios Jun 28 '12 at 10:34
  • 7
    `/dev/stdin` or `/dev/stdout` can be used if you really want an input/output stream. Note that it is a stream, programs that want to seek in a file may not work properly with it as would be the case with `-` (e.g. ffmpeg) – Lekensteyn Jun 28 '12 at 11:49
  • 4
    In the case of `bash`, the hyphen *is* interpreted by the shell. See the [Advanced Bash-Scripting Guide - Chapter 3. Special Characters](http://tldp.org/LDP/abs/html/special-chars.html), then search for the text [dash] or "redirection from/to stdin or stdout". Using `bash` you can use the hyphen most places expecting a filename. It's an obvious complement to < | > IMHO – bsd Jul 03 '12 at 19:32
  • 6
    I'm not convinced that's the case. First, `cat` handles `-` (check the manpage). A shell-builtin version of `cat` might or might not, but that's not strictly the entire shell. Also, if the shell handled `-`, you could say echo `-` and it would expand to something else. Instead, it just echoes a dash (not `/dev/stdin` or `/proc/self/fd/0`). And `echo test > -` just creates a file called `-`, so it clearly doesn't handle it there either. Oh, and the page you listed doesn't say it's handled by the *shell*, it says you can use it with `cat` and `diff`, both of which understand dashes explicitly. – Alexios Jul 04 '12 at 08:14
  • 1
    I think you're right and I'm wrong. The doc lists cat, etc as *examples* but after scouring the source of bash I see no code handling the `-` ,however in the coreutils I found a reference to it in arg processing of several commands. Apparently the shell itself does NOT process the `-`, my mistake. – bsd Jul 06 '12 at 12:22
  • For example, in `tcpdump`,`-w file (-w -)` it means *Standard output*. *"Standard output is used if file is `-`. "* – Rick Aug 02 '22 at 08:05
15

In this case, the - is actually pretty useless, assuming you're running Linux:

GNU tar (the version on Linux) accepts its input from the standard input by default. If you do not want this behaviour, and want to pass the file name as a command line argument, then you need to specify the flag f:

tar xf filename

So this is the same as

tar x < filename

Or, if the input is gzipped as in your example:

gzip -dc filename | tar x

It isn’t meaningful to specify the f flag here at all, but because it was specified, the filename needs to be given as - to indicate that we want to read from standard input (see other answer). So, to repeat, this is redundant and slightly weird.

Furthermore, the above line can be simplified because GNU tar can be told to stream the input through gzip itself by specifying the z flag:

tar xfz filename

– No need to call gzip explicitly.

Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
Konrad Rudolph
  • 3,689
  • 3
  • 23
  • 29
  • 1
    Note: not every `tar` has `z` option. – liori Jun 28 '12 at 14:53
  • "redundant and slightly weird" - Sometimes being explicit aids in clarity. – Dennis Williamson Jun 28 '12 at 23:10
  • 2
    Most OSes other than Linux have `tar` defaulting to the first tape drive, for historical reasons. – Gilles 'SO- stop being evil' Jun 28 '12 at 23:31
  • @Dennis I agree that explicitness is good, but I disagree that this is the case here: you are explicitly telling `tar` to use a file as input rather than its default, which is from a stream. And *then* you go on telling it “you know, never mind, here’s a stream anyway”. – Konrad Rudolph Jun 29 '12 at 06:49
  • 1
    @Gilles *and* BSD, *and* OS X, …. But I’m curious: what other systems except in a few old mainframes still use such a version (what systems other than mainframes do even *have* a tape drive)? – Konrad Rudolph Jun 29 '12 at 06:51
  • 1
    @KonradRudolph All three major BSDs default to a tape drive (`/dev/sa0` on FreeBSD 9.0, `/dev/rst0` on NetBSD 6.0 and OpenBSD 5.1). AIX 7.1 defaults to `/dev/rmt0`. MINIX3 defaults to `/dev/sa0`. (I checked the latest OS version in each case, these aren't “old mainframes”.) Solaris is configurable through a file in `/etc`, which I think defaults to a tape drive. GNU tar, Schilling tar, OSX and BusyBox default to stdin/stdout. – Gilles 'SO- stop being evil' Jun 29 '12 at 07:46
  • 1
    @Gilles - I recompiled `tar` to default to the *second* tape drive, for obvious reasons. :) – David Harkness Jun 29 '12 at 09:09
  • Solaris is one of them, too. On the last Solaris machine I'm running, `tar` defaults to `/dev/rmt/0`. The only lesson here is ‘explicit is better than implicit’. – Alexios Jun 29 '12 at 11:11