How can I provide stdin to ed, which need a filename?

1.9k views Asked by At

Need some unix shell basic here:

For command that I see no "-" target in , say ed:

print '%-2p\nq' | ed -s FILE

Can I provide a stream from stdout of some cmd, rather than FILE name, as the data to be processed:

SomeCMD | ed -s SOMETHING_MAGICAL <<< 'print '%-2p\nq'

Is is possible?

3

There are 3 answers

1
itsbruce On BEST ANSWER

ed reads its commands from stdin, so if your file is also on stdin, how do you work?

In fact, you can feed file input over stdin, if you concatenate its output with a single line

i

at the beginning, to start writing in the data, then append a single . to end the input, followed by any commands. You can even output the results to stdout. Do remember that it will break if there is a line in the file with nothing but a single . in it.

So if a file input.file contains this:

First line
Second line
Third line

And a file commands.list contains this:

.
1d
1,$w /dev/stdout

Then this command line...

echo i | cat - input.file commands.list | ed -s

Will output this:

Second line
Third line

Dare I say tadaaaaa! ?

Note: you can probably protect against the case of single . lines in the file by piping the file through a filter that escapes any such lines and then unescaping them again with ed commands. I leave that to your ingenuity.

Another note: you really should use sed for this, but I couldn't let the it can't be done comments go by.

0
don_crissti On

You use r to read a command output into the text buffer. So, portable:

printf '%s\n' 'r !df -h' g/tmpfs/d ,p q | ed -s

or

ed -s << IN
r !df -h
g/tmpfs/d
,p
q
IN

The above reads in the output of df -h, deletes the lines matching tmpfs and prints the result.
If your shell supports process substitution:

printf '%s\n' g/tmpfs/d ,p q | ed -s <(df -h)

With gnu ed that SOMETHING_MAGICAL is called !.
As per the man page:

Start edit by reading in 'file' if given. If 'file' begins with a '!', read output of shell command.

printf '%s\n' g/tmpfs/d ,p q | ed -s '!df -h'

or, with herestring:

ed -s '!df -h' <<< $'g/tmpfs/d\n,p\nq\n'
0
Tasos Papastylianou On

Yes. Effectively, instead of 'piping' into ed, you can use 'process substitution' to pass the output of your command as the input to be edited, leaving the standard pipe free to take pre-scripted ed commands.

Example:

echo '#
,s/\/dev\/\(\w*\) .* \b\(.*\)%.*$/DEVICE \1 is \2% full!/
,p
Q' | ed -s <(df 2> /dev/null | tail -n +2 | egrep "^/dev/")

DEVICE sda6 is 90% full!
DEVICE sda2 is 88% full!

Explanation:

Process substitution (the <() part) turns the output of df 2> /dev/null | tail -n +2 | egrep "^/dev/" into the contents of a temporary file descriptor, which is then used as an input file to ed -s.

At the same time, ed commands are passed via echo into a pipe.

Echo here is used in multiline single-quote mode without interpretation of escape sequences; if you're not too bothered about not having everything appear on a single line, then this is the most straightforward way to pass ed commands without having to go into escape-sequences hell.

Specifically, we are passing four ed commands:

  • A comment (just to align the remaining commands on the console)
  • A substitution command
  • A 'print all' command
  • A 'quit unconditionally' command, to prevent any warning messages that could have been printed on the terminal.