4

I've been asked to re-create this command in C, with no additional information as to what cmd1 could be.

< file1 cmd1 | cmd2 > file2

My question resolves around the first character of this command: the <.

Let's ignore the command after the pipe, and pretend cmd1 is cat.

I can thus replace < file1 cat with cat file1, which is much easier to do in C. But is this approach valid when it comes to other commands?

I've tested both cat and sed with these two commands:

< Makefile cat
cat Makefile

And

< Makefile sed 'p'
sed 'p' Makefile

Both print out the same result. So is it safe to assume I can interpret < file1 cmd1 as cmd1 file1?

5
  • 6
    No they aren't the same. Some commands may not interpret one of its arguments as input.
    – konsolebox
    Mar 16 at 15:37
  • 1
    Redirection happens before command is exec()'d. I think what you'll have to do here is do a pipe-fork and in the first process, open file1 and replace fd0 with it. In the second process, open file2 and replace fd1 with it.
    – konsolebox
    Mar 16 at 15:41
  • 1
    In any case, you'd need to handle the output redirection as an actual redirection, so trying to skip on the input one isn't going to help much.
    – ilkkachu
    Mar 16 at 15:47
  • @ilkkachu: Not to mention, you need to do both an input and an output redirection to make the pipe work.
    – Kevin
    Mar 17 at 5:04
  • 1
    Your question title contains backticks but the question body does not. Noting that backticks in the most popular shells have a special meaning, please clarify. Mar 17 at 8:20

1 Answer 1

18

No, you can't.

While there are many programs, like most of the common text processing tools (sed, cut, grep etc.) that read the data to process from files listed as command line arguments, or read it from stdin if no files are given, that's not the case for all programs there are. Command line arguments are different from data provided via stdin, and it's wholly up to the program how to process them.

The obvious counterexamples are programs like rm, which don't read stdin at all, but even with ones where you might think the equivalence would hold, there are filter-like commands such as tr and wc which don't take a filename arg at all, or produces different output.


The command line syntax of tr is roughly:

tr [options] string1 [string2]

It doesn't take any filenames as arguments, but always reads its stdin.

Hence, turning

< file.txt tr abc xyz

into

tr abc xyz file.txt

will just produce an error.


As mentioned in the comments, wc is another common tool that also behaves differently, though it's a bit less extreme. With the filename given, it includes it in the output (even if there's only one, unlike with grep):

$ wc hello.txt 
       1       1       4 hello.txt
$ wc < hello.txt
       1       1       4

Also many programs take the filename - as an explicit instruction to read stdin, but the shell doesn't support that. So while cat < - reads a file called -, cat - reads from cat's stdin, likely the terminal.

5
  • 1
    Also see: wc, the classic example of a program with different behaviour in the two cases
    – muru
    Mar 16 at 15:57
  • 1
    Also <answers rm -i file vs rm -i file answers... Mar 16 at 16:53
  • See also cat - vs < - cat Mar 16 at 16:53
  • Ah yes I see you point thanks a lot :), but you may want to correct wc, as I believe it does produce the same result... It should be < hello.txt wc in the second example Mar 16 at 18:56
  • 5
    @HerbieVine, < hello.txt wc is the same as wc < hello.txt in Bourne-like shells. Both run wc which no argument (well strictly speaking with one argument, argv[0[ being wc) and with fd 0 redirected on hello.txt opened in read-only mode. Redirections can appear anywhere on the command line. Mar 16 at 20:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.