0

OS: Mac OS

cat file.txt || ./a.out, it works, but cat file.txt | ./a.out not work, why?

Where can I find the documents to learn it(I don't how to search it...)?

c code:

#include <stdio.h>

int main(int argc, char *argv[]) {
  while (*++argv)
    printf("%s\n", *argv);
  return 0;
}
erik258
  • 14,701
  • 2
  • 25
  • 31
rax
  • 11
  • 3
  • 3
    What does this have to do with the C language? – kaylum Sep 29 '22 at 11:44
  • 1
    Both `cat file.txt || ./a.out` and `cat file.txt | ./a.out` work, but they do very different things. – William Pursell Sep 29 '22 at 11:49
  • @kaylum I have added the c code, please look at it. – rax Sep 29 '22 at 11:51
  • 2
    Please define "works" and "not work". Both commands do something and we can't say (but could guess) what "works" means unless you tell us what you are expecting that to do. – kaylum Sep 29 '22 at 11:52
  • 2
    Since you are trying to understand shell syntax, it's reasonable to look through the documentation for your shell. The bash man-page describes both operators fairly well. – William Pursell Sep 29 '22 at 11:58
  • In your example of a command that "works", it's `cat` writing to the screen, not `a.out` doing anything at all -- it isn't even run. `xargs ./a.out – Charles Duffy Sep 29 '22 at 12:06

2 Answers2

1

these are two different things

cat file.txt | ./a.out :

the output of cat file.txt will be given as input of ./a.out


cat file.txt || ./a.out :

it's an "OR" operator, if cat file.txt fail, ./a.out will be executed, but if cat file.txt succeeds, ./a.out will not be executed.

1

|| and | as you show them are unix shell operators. They may look similar, but || and | are totally different.

| is the pipe operator. It connects the standard output of the left command to the standard input of the right command.

By default standard output of each command is the terminal screen.

% echo -e "a\nb\nc"                                                                                                                                                         
a
b
c

But the | operator lets us redirect that standard output to the standard input of the next command:

% echo -e "a\nb\nc" | grep a                                                                                                                                               
a

The shell handles opening up a pipe and connecting its output and input file descriptors to the left and right commands respectively. The actual commands thus don't generally have to know or care whether their output is a terminal, a file, another program behind a pipe.

|| is the logical OR operator. It runs the second command if the first command does not return success exit code (ie 0).

% test -f /usr/local/bin || echo "/usr/local/bin is not a file"                                                                                                            
/usr/local/bin is not a file
% test -f /bin/bash || echo "/bin/bash is not a file"

There is also a logical and operator that does the opposite:

% test -f /bin/bash && echo "/bin/bash is a file"                                                                                                                       
/bin/bash is a file

And that in turn should not be confused with the & operator, which puts the command in the background.

% sleep 3 &                                                                                                                                                                 
[1] 55981
% jobs                                                                                                                                                                      
[1]  + running    sleep 3
% fg                                                                                                                                                                        
[1]  + running    sleep 3
% 

In general, shell syntax can be rather esoteric, and you should be aware that every shell is a little different (eg c/ bourne / korn shells vs bash vs zsh, the latter being now the standard on Mac Os)

This is all completely distinct from the command line arguments you access via argv and argc. If you wanted the standard output of one command to be converted to arguments to the second command, xargs can do it.

erik258
  • 14,701
  • 2
  • 25
  • 31