3

I have been struggling with this issue for a while now and would really appreciate it if someone could clarify it for me . Suppose I am trying to pipe the two commands together. readlink and cat

readlink Command output
$ readlink -f SUService.log
/cygdrive/c/SUService.log

Now if I try something like this (it fails)

$ readlink -f SUService.log | cat

While something like this will work

$ readlink -f SUService.log | xargs cat

I wanted to know why that is ? I have read this post here in which the OP had a similar question and this post which attempts to explain difference between an argument and an input however i still couldnt wrap my head around the accepted answer(s). From what I understand is that readlink returns the result to stdout which is the terminal screen while cat wants an input as argument. This in return prompts me to ask how do I know if the output of a command (such as locate or readlink) can work as an argument or not for the next command ? I have been doing more reading and it turns out i would like to know when I should be using the xarg command ?

MistyD
  • 147
  • 2
  • 8
  • I don't have time for a lengthy answer, but `stdout` can act as an arugment if the shell supports [process substitution](http://tldp.org/LDP/abs/html/process-sub.html). – slhck Mar 16 '15 at 19:39
  • I wrote this on superuser, but this may help: [pipe output to other command](http://superuser.com/a/189386/8804) – Rich Homolka Mar 16 '15 at 22:36

3 Answers3

6

The following command does not fail. It simply does something you didn't expect:

readlink -f SUService.log | cat

When cat is given stdin, it copies it to stdout. It does not look for filenames in it.

Alternatively, this will read from the named file:

cat "$(readlink -f SUService.log)"

xargs will also put the name on the cat command line, yielding the same result:

readlink -f SUService.log | xargs cat
John1024
  • 16,593
  • 5
  • 50
  • 45
  • thanks for explaining that but what I am looking for is when would i need to use xarg command ? – MistyD Mar 16 '15 at 20:19
  • 2
    Use `xargs` when you want to use stdin as the arguments on a command line. `echo filename | xargs cat` is the same as `cat filename`. – John1024 Mar 16 '15 at 20:30
4

your example is rather confused.

You don't normally send just any characters to cat.

You normally send a file to cat.

Nevertheless, when you do send some characters to cat, it prints the characters.

$ echo abc12123 | cat
abc12123

Normally you send a filename to cat

$ cat abc12123
cat: abc12123: No such file or directory

So notice that cat itself, deals differently with funny characters piped to it, vs being passed them as a parameter.

$ cat b.b
textofb.b

$ echo b.b | cat
b.b

$ cat b.b
textofb.b

i'll use a simpler example than yours

$ echo b.b | xargs cat
textofb.b

see it prints the contents of b.b because asdfasdfs | xargs cat, will send the output of asdfasdfs as a parameter to cat.

So

echo b.b | xargs cat   
=  
cat b.b

Whereas echo b.b | cat is not the same as cat b.b

barlop
  • 23,380
  • 43
  • 145
  • 225
  • Is there a way for me to tell if a certain command will send the output as a parameter as well ? – MistyD Mar 16 '15 at 20:23
  • @MistyD yeah, `echo asdfsd | command`, and `command asdfasdf`, and see what it does. That's easier than reading a long man page which is the other way. but you learn by both trying and reading. – barlop Mar 16 '15 at 20:24
  • As for when to use xargs, I suppose, if you have a command, and you can't pipe to it, and you want to send the output of a command to it, and it only takes a parameter, then you could use xargs. or I suppose, command substitution. Personally, I think I may have used xargs once in Windows cmd to allow me to send info from a command, to a batch file(script) I wrote. I couldn't pipe to my batch file but my batch file could take a parameter. windows cmd shell doesn't have substitution so I think I got a copy of xargs and used that. – barlop Mar 16 '15 at 20:32
  • cmd has a usage of the 'for' command that can send the output of a command to another command, as a parameter, but the linux solution - xargs is neater looking, and you can get xargs for windows. so that was when I used xargs. – barlop Mar 16 '15 at 20:59
  • john gives a good example based on yours.. cat is perhaps unusual in that piping to it has a different effect to giving a parameter, so if you wanted to pipe to cat but have it have the effect of sending it as a parameter, then use xargs. e.g. you want to pipe a filename to cat, but have the contents of the file outputted. – barlop Mar 16 '15 at 21:06
  • @barlop On the other hand, if you think of stdin as just another file, then the `cat` behavior is consistent: it prints out stdin just as it would a file supplied as an argument. – John1024 Mar 16 '15 at 21:11
  • @John1024 well, then you're piping/giving it the contents of the file vs giving it the filename, which isn't that consistent. But putting that aside.. if cat by the perspective you pur forth, is consistent, then what would that say about echo? (I guess if using that perspective, one would have to say echo is inconsistent) – barlop Mar 16 '15 at 21:21
  • 1
    @barlop It seems to me that there are two categories of commands here. In one category, `cat`, just like `sed` and `awk`, will accept input from stdin just as it would input from a file named on the command line. In the other category, commands, such as `echo`, `date`, and `ls`, do not use stdin at all. – John1024 Mar 16 '15 at 21:28
  • @John1024 ah for some reason I thought you could pipe to echo, my bad And you make a great point re e.g. sed – barlop Mar 16 '15 at 21:37
2

Take a look at the manpages for cat and xargs to see what they do.

man cat

cat - concatenate files and print on the standard output

And:

man xargs

xargs - build and execute command lines from standard input

Here's a little demo

Let's create a test file:

echo "a" > test
echo "b" >> test
echo "c" >> test

cat

cat test

Reads the file and gives:

a
b
c

echo | cat

echo test | cat

According to man cat, this does the same as:

echo test | cat -

Which pipes test into cat's stdin, and tells cat to read from stdin.

echo | xargs cat

echo test | xargs cat

Generates and executes the following command:

cat test

The output of this we've already shown.

If we run

<test xargs -n1 cat

Xargs sees this on input:

a
b
c

And it generates the following commands:

cat a
cat b
cat c

Which should result in three errors since those files do not exist.

Why the -n1?

According to man xargs, the -n1 tells xargs to use one argument (read from stdin) in each command that it generates.

If we use -n2 instead, we generate the following which uses up to two parameters per command:

cat a b
cat c

And if we use -n3 or higher, or simply omit the -n:

< test xargs cat

We get:

cat a b c
Mark K Cowan
  • 698
  • 1
  • 6
  • 13