Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Piping the output of a program that doesn't write to stdout

Tags:

bash

I'm looking for the best way to use pipes when the input program doesn't write to stdout. Specifically I want to pipe objcopy into hexdump like this

objcopy -I ifmt -O binary ifile - | hexdump -C

but objcopy doesn't accept '-' as a file meaning 'write to stdout' as some programs do.

At the moment I am doing

objcopy -I ifmt -O binary ifile tmpfile; hexdump -C tmpfile; rm tmpfile

but was wondering if there was a better way.

I am using bash 4.1.10 on cygwin.

like image 310
Peter Hull Avatar asked Oct 18 '25 13:10

Peter Hull


1 Answers

I wrote a comment prescribing a process substitution, but it can't work for objcopy since objcopy will try to open a seekable file (as it may need to move back and forth in the file).

In short: objcopy can't write to a stream as stdout, that's why its output must be a file that can be seeked. Your solution is very likely the only reasonable possibility.


To answer your question

I'm looking for the best way to use pipes when the input program doesn't write to stdout

in a more general fashion (but that's not applicable with objcopy or any command that requires seeking the file), in Bash you can use process substitution: if mycommand takes a parameter that is an output file, and doesn't accept - for standard output and doesn't write to standard output by default, you can use it as:

mycommand >(cat)

or if you want to pipe it through, e.g., hexdump -C:

mycommand >(hexdump -C)

With this, mycommand will see an argument of the form /dev/fd/42 (where 42 may differ), and will be able to open it for writing, as if it where a regular file (but not seekable), and hexdump will get on its standard input the written data.

You can experiment process substitution like so: call the following script mycommand:

#!/bin/bash

if [[ $1 ]]; then
    echo "Hi, this is mycommand, and I was called with first argument: \`$1'"
    echo "I'm outputting this to the file given as argument" > "$1"
else
    echo >&2 "Please provide an argument (file to write to)"
    exit 1
fi

This script makes sure that you give a non-empty argument (otherwise shows an error message), outputs this argument to standard output, and a little line in the file the name of which is given as argument.

Then chmod +x mycommand and play with it:

$ ./mycommand
Please provide an argument (file to write to)
$ ./mycommand -
Hi, this is mycommand, and I was called with first argument: `-'
$ ls
- mycommand
$ rm ./-
$ ./mycommand >(cat)
Hi, this is mycommand, and I was called with first argument: `/dev/fd/63'
I'm outputting this to the file given as argument
$ ./mycommand >(tr -d e)
Hi, this is mycommand, and I was called with first argument: `/dev/fd/63'
I'm outputting this to th fil givn as argumnt
$ ./mycommand >(hexdump -C)
Hi, this is mycommand, and I was called with first argument: `/dev/fd/63'
00000000  49 27 6d 20 6f 75 74 70  75 74 74 69 6e 67 20 74  |I'm outputting t|
00000010  68 69 73 20 74 6f 20 74  68 65 20 66 69 6c 65 20  |his to the file |
00000020  67 69 76 65 6e 20 61 73  20 61 72 67 75 6d 65 6e  |given as argumen|
00000030  74 0a                                             |t.|
00000032
$ ./mycommand >(cat) > /dev/null
I'm outputting this to the file given as argument
like image 132
gniourf_gniourf Avatar answered Oct 21 '25 01:10

gniourf_gniourf



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!