Using -
as a filename to mean stdin/stdout is a convention that a lot of programs use. It is not a special property of the filename. The kernel does not recognise -
as special so any system calls referring to -
as a filename will use -
literally as the filename.
With bash redirection, -
is not recognised as a special filename¹, so bash will use that as the literal filename.
When cat
sees the string -
as a filename, it treats it as a synonym for stdin. To get around this, you need to alter the string that cat
sees in such a way that it still refers to a file called -
. The usual way of doing this is to prefix the filename with a path - ./-
, or /home/Tim/-
. This technique is also used to get around similar issues where command line options clash with filenames, so a file referred to as ./-e
does not appear as the -e
command line option to a program, for example.
¹ Except for the >& filename
operator that bash eventually copied from csh to redirect both stdout and stderr, where >&-
is still about closing file descriptors like in the Bourne shell, even when -
is quoted or the result of an expansion which means that >&
operator can't be used for arbitrary file names. Use the standard/Bourne > "$file" 2>&1
syntax or the bash-specific &> "$file"
instead.
2>&-
construction, which means "close descriptor 2".