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

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
  • 17,343
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
  • 25,198
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