What does "-" mean in this linux command? - linux

I am learning the cat command of linux, and I found this command :
$ echo 'Text through stdin' | cat - file.txt
What does "-" mean here? If I don't type it , then 'Text through stdin' will not be shown.

it is common to write stdin as dash (-).
even man cat mentions that:
With no FILE, or when FILE is -, read standard input.
and the manpage even has an example illustrating the use of dash and ordinary filenames (which is quite close to your original question, but includes the answer):
cat f - g
Output f's contents, then standard input, then g's contents.

- tells cat to read from stdin. This is quite common, a lot of apps read from stdin if you pass - to them.
Some apps use - as stdout.
Here is an example of downloading blender and instead of writing it to a file we write it directly to stdout and pipe it to tar, which expands it on the fly during download.
wget -c https://download.blender.org/source/blender-2.90.1.tar.xz -O - | tar -xzv
Here the -O - tells wget to write directly to stdout

$ echo 'Text through stdin' | cat - file.txt
- tells cat to read from standard input, in this case, from the pipe, i.e, what echo 'Text through stdin' outputs.

Related

why can't pass file path argument to shell command 'more' in pipeline mode?

I have a text file a.txt
hello world
I use following commands:
cmd1:
$ more a.txt
output:
hello world
cmd2:
$ echo 'a.txt'|more
output:
a.txt
I thought cmd2 should equal to echo 'a.txt'|xargs -i more {},but it's not.
I want to know why cmd2 worked like that and how to write code which work differently in pipeline mode.
Redirection with | or < controls what the stdin stream contains; it has no impact on a program's command line argument list.
Thus, more <a.txt (efficiently) or cat a.txt | more (inefficiently) both attach a file handle from which one can read the contents of a.txt to the stdin file handle of a new process before replacing that process with more. Similarly, echo a.txt | more makes a.txt itself the literal text that more reads from its stdin stream, which is the default place it's documented to get the input to display from, if not given any more specific filename(s) on its command line.
Generally, if you have a list of filenames and want to convert them to command-line arguments, this is what xargs is for (though using it without a great deal of care can introduce bugs, potentially-security-impacting ones).
Consider the following, which (using NUL rather than newline delimiters to separate filenames) is a safe use of xargs to take a list of filenames being piped into it, and transform that into an argument list to cat, used to concatenate all those files together and generate a single stream of input to more:
printf '%s\0' a.txt b.txt |
xargs -0 cat -- |
more

Confused about some standard input or heredoc usage in shell

As the image. All commands are similar.
I know how to use that, but I don't really know the detail.
Would anyone know that? Thank you very much.
# does `cat` read fd and print?
$ cat file
# does `cat` read from stdin and print?
$ cat < file
$ cat - < file
# with heredoc or herestring, what methods `cat` command use to read from heredoc?stdin?
$ cat << EOF
heredoc> test
heredoc> EOF
test
$ cat <<< "test"
$ cat - << EOF
heredoc> test
heredoc> EOF
test
$ cat - <<< "test"
# and I dont why these commands works?
$ cat <(echo "test")
$ cat - <<(echo "test")
# why this command doesn't work?
$ cat - <(echo "test")
Some reading material, all from the very useful Bash manual:
Redirection (<filename) -- causes standard input to be redirected to the file filename
Here documents (<<WORD) -- causes standard input to be redirected to the script source from the next line, up to but not including the line WORD
Here strings (<<<"string") -- causes standard input to be redirected to the string string (as though the string were written to a temporary file and then standard input redirected to that file)
Process substitution (<(command)) -- starts a process executing command and inserts a name onto the command line which acts like a filename, such that reading from that "file" produces the output of the command
The use of - to indicate the the source file is standard input is common to many commands and recommended by Posix. Many commands read from standard input if no file is specified. Some, like cat, implement both ways of indicating that the intention is to read from standard input.
Note that - and <(command) are both filename arguments, while <filename, <<WORD and <<<"string" are redirections. So while they superficially look similar, they are quite different under the hood. What they have in common is that they have to do with input; some of them (but not here-docs/strings) have analogues that have to do with output, using > instead of <.

How to take advantage of filters

I've read here that
To make a pipe, put a vertical bar (|) on the command line between two commands.
then
When a program takes its input from another program, performs some operation on that input, and writes the result to the standard output, it is referred to as a filter.
So I've first tried the ls command whose output is:
Desktop HelloWord.java Templates glassfish-4.0
Documents Music Videos hs_err_pid26742.log
Downloads NetBeansProjects apache-tomcat-8.0.3 mozilla.pdf
HelloWord Pictures examples.desktop netbeans-8.0
Then ls | echo which outputs absolutely nothing.
I'm looking for a way to take advantages of pipelines and filters in my bash script. Please help.
echo doesn't read from standard input. It only writes its command-line arguments to standard output. The cat command is what you want, which takes what it reads from standard input to standard output.
ls | cat
(Note that the pipeline above is a little pointless, but does demonstrate the idea of a pipe. The command on the right-hand side must read from standard input.)
Don't confuse command-line arguments with standard input.
echo doesn't read standard input. To try something more useful, try
ls | sort -r
to get the output sorted in reverse,
or
ls | grep '[0-9]'
to only keep the lines containing digits.
In addition to what others have said - if your command (echo in this example) does not read from standard input you can use xargs to "feed" this command from standard input, so
ls | echo
doesn't work, but
ls | xargs echo
works fine.

About the composition of Linux command

Assuming:
the path of file f is ~/f
"which f" shows "~/f",
Then,
which f | cat shows ~/f. So cat here is applied to the quotation of ~/f, which is different with cat ~/f.
My question is: how I could use one command composed of which and cat to achieve the result of cat ~/f? When I don't know the result of which f in advance, using this composition can be very convenient. Currently, if I don't know the result of which f in advance, I have to invoke which f first, and copy-paste the result to feed less.
A related question is: how can I assign the result of which f to a variable?
Thanks a lot!
Try:
cat `which ~/f`
For the related question:
foo=`which ~/f`
echo $foo
cat "`which f`"
Like so in bash:
cat "$(which f)"
var="$(which f)"
What you want is:
cat `which f`
In which f | cat the cat program gets the output of which f on standard input. That then just passes that standard input through, so the result is the same as a plain which f. In the call cat ~/f the data is passed as a parameter to the command. cat then opens the file ~/f and displays it's contents.
To get the output of which f as a parameter to cat you can, as others have answered, use backticks or $():
cat `which f`
cat $(which f)
Here the shell takes the output of which f and inserts it as a parameter for cat.
In bash, you can use:
cat "$(which f)"
to output the contents of the f that which finds. This, like the backtick solution, takes the output of the command within $(...) and uses that as a parameter to the cat command.
I prefer the $(...) to the backtick method since the former can be nested in more complex situations.
Assigning the output of which to a variable is done similarly:
full_f="$(which f)"
In both cases, it's better to use the quotes in case f, or it's path, contains spaces, as heinous as that crime is :-)
I've often used a similar trick when I want to edit a small group of files with similar names under a given sub-directory:
vim $(find . -type f -name Makefile)
which will give me a single vim session for all the makefiles (obviously, if there were a large number, I'd be using sed or perl to modify them en masse instead of vim).
cat echos the contents of files to the standard output. When you write stuff | cat, the file cat works on is the standard input, which is connected to the output of stuff (because pipes are files, just like nearly everything else in unix).
There is no quoting going on in the sense that a lisp programmer would use the word.

Linux: How would I pipe text into a program properly?

I've looked but can't find anything. A program for example, a TTS I use lets you do the following:
~#festival -tts | echo "I am to be spoken"
Which is really nice, but for programs I use such as hexdump, I don't know how to pipe text into it. I can REALLY use some of these things, some examples I tried (but failed) are like so:
~#gtextpad < dmesg
//(how do I put the contents into the text pad for display? not just into a file)
~#hexdump | echo "I am to be put into hexdump"
//(How do I get hexdump to read the echo? It normally reads a file such as foo.txt..)
here are some ways to pass text to hexdump
Stdin:
echo "text" | hexdump
Here document
hexdump <<EOF
text
EOF
to process entire file
hexdump file
On bash, you can also do
hexdump <<< "Pipe this text into hexdump"
The data flow in a pipeline (series of commands separated by pipe symbols) flows from left to right. Thus, the output from command1 below goes to the input of command2, and so on.
command1 |
command2 |
command3 arg1 arg2 arg3 |
sort |
more
So, to get the output of 'echo' into 'hexdump', use:
echo "I am to be dumped" | hexdump
I don't see how the 'festival' command you show can work. The shell does enough plumbing that without making unwarranted assumptions and doing a lot of skulduggery and then still relying on scheduling decisions in the kernel to get things 'right', I don't see how it can be made to work.
From the hexdump(1) man page:
The hexdump utility is a filter which displays the specified files, or the standard input, if no files are specified, in a user specified format.
So:
echo "I am to be put into hexdump" | hexdump

Resources