1

This is what I am trying to achieve step by step:

  1. ls
  2. then reverse it's output
  3. then add a new line to the last of this file

Accordingly, I have made the following one line script but it's giving error

(ls | tac | echo >>) > ./foobar

I can do this by splitting into multiple commands but I am trying to do this in one single command.

I am confused because echo >> ./foobar inserts a new line to the end of file.

Then why is my line of code not working? Why echo >> is not adding new line at the end of file descriptor but giving error instead? What am I doing wrong here?

  • What happens when you do ls | tac | echo >>. Do you get a result that you expect? – KevinO Jun 30 '17 at 20:25
  • 4
    AFAIK echo doesn't accept standard input; you probably want to simply chain the commands e.g. ( ls | tac; echo ) > foobar or if your shell supports command grouping { ls | tac; echo; } > foobar avoiding the subshell – steeldriver Jun 30 '17 at 20:33
  • @steeldriver got my answer, yes you're right – GypsyCosmonaut Jun 30 '17 at 20:35
  • 4
    In the spirit of simplification, the same results can be achieved using native ls options, eliminating the need for the useless tac. Try ls -1r instead. – Timothy Martin Jun 30 '17 at 20:40
1

Here's how your command is parsed:

  • (…) is a compound command. The content of the parentheses is executed in a subshell.
    • ls | tac | echo >> is a pipeline consisting of three parts: ls, tac and echo >>. The leftmost part's output is connected to the second part's input, and the second part's output is connected to the rightmost part's input.
    • ls is a simple command, executing an executable file.
    • tac is a simple command, executing an executable file.
    • echo >> is not syntactically correct. The >> operator needs to be followed by a file name, and the file name is missing.
  • > ./foobar redirects the output of the compound command to the file ./foobar.

Directing input to echo doesn't make sense: it doesn't read any input. To use echo to append to the output of some other command, run echo after the other command, not in parallel.

ls | tac; echo

The output of echo is going to the same place as the output of tac, so there's no need for any redirection.

( ls | tac; echo ) >./foobar

You don't need a subshell here. A simple grouping will do. (See Simple logical operators in Bash for a summary of bash's parenthesis-like operators.)

{ ls | tac; echo; } >./foobar

Using the >> operator to append would only be needed if you were appending to an already-existing file. This is not the case here: all the commands go to the same location, the file foobar is only opened once, and remains open as long as the whole compound command is executing. The >> operator would be needed if you opened the file twice:

ls | tac >./foobar; echo >>./foobar
3

The >> tells the shell to append the commands output to the filename directly following the symbols (so you would at least have to add a name before the closing bracket).

For what you would like to do, you could either do:

ls | tac > ./foobar; echo >>./foobar

or:

(ls | tac; echo ) >./foobar

Both are achieving the same result.

2

To achieve the result as specified, it is possible to do:

echo -e "`ls | tac`\n" > ./foobar

In this way, the output of ls is piped through tac. The result is contained within the echo command, and the escape character interpretation of echo will add a new line. The stdout can then be redirected to a file.

I do not believe it is possible to pipe stdout into echo.

  • Doesn't work with file names containing backslashes. – Gilles Jul 2 '17 at 21:03
  • @Gilles, then don't do that :) While I agree there are corner cases, there is also worrying about things that 99% of people don't do, and no where was it enumerated as a requirement. As also noted, there may not be the need for the tac command, using instead ls -1r for example. – KevinO Jul 2 '17 at 22:17

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.