2

I have been Googling for this and searched Stack, but didn't find the exact thing I want to do. I really can't get my head around this yet.

So, let's say I have sh script which is only a wrapper of gzip (just as an example). On the commandline I want to pipe the output of something (say mysqldump) to my script. That script must then take the input and pipe that through to gzip.

Example of commandline:

mysqldump somedb | myscript > somefile.dmp.gz

Example of myscript (something I tried):

#!/usr/bin/env sh
read inp
command="echo \"$inp\" | gzip"
eval $command

Probably a lot of things are wrong with this example. Please help? :)

Solution (for others looking for it)

Thanks to the explanations below I now understand that executing a command in a SH-script, will simply take the input piped to the script just as well as when the command was being executed directly.

So in this case:

cat file | gzip

will do exactly the same as:

myscript:

#!/usr/bin/env sh
gzip

cat file | ./myscript

So I would like to point out that in my case there was another problem as well: In my real-world script I tried to check whether there was an input stream by reading it like this:

read inp
if [ -z "$inp" ]; then
    echo "No input"
    exit;
fi

It turns out that after the read inp, the input pipe is empty.

  • Your edited question contains somewhat of a different question. To answer it, we need to know how the script is invoked. – Kusalananda May 19 '17 at 8:05
  • Yes thank you, however for now I don't need an answer to that. I simply mentioned it for future reference for others. – vrijdenker May 19 '17 at 8:34
  • Ah, a misunderstanding on my part. – Kusalananda May 19 '17 at 8:35
3
#!/bin/sh
gzip -c

That would be enough.

$ mysqldump ... | ./script >out.gz

gzip -c will read uncompressed data on its standard input and write compressed data to its standard output.

The standard input is provided by the pipe and the standard output is redirected to a file. The piping and redirection is taken care of by the calling shell.

A slightly more complex example that will take a sed expression on the command line and transform the input according to that, or just forward the data if no expression was used:

#!/bin/sh

if [ -n "$1" ]; then
    sed -e "$1"
else
    cat
fi

(here, using sed -e "" would have had the same effect as cat, but I wanted a more complex example)

$ utility | ./script "1,5d" >out

... would delete the first five line of output from utility.

  • Thanks for the explanation. It works now. Apparently by writing a more complex script (my actual script does a lot more ofcourse) I made this thing more complex than it should be. I will add an extra notice to my post which may help others as well. – vrijdenker May 19 '17 at 7:48
2

I'm not sure which part of your script is simple misunderstanding and which is complexity because you're trying to illustrate a complex situation in a simpler example.

Having said that, this will do what your question asks:

#!/bin/sh
gzip "$@"
1

To use read, to read some of the input to check if it's empty or not, you'd have to use a shell like zsh that can store any byte value in its variables like:

#! /bin/zsh -
if LC_ALL=C read -ru0 -k1 byte; then
  # one byte was read, the input is not empty
  (printf %s "$byte"; cat) | gzip
else
  echo >&2 No input
fi

Or use some form of encoding:

#! /bin/sh -
# get the value of the first byte as octal:
byte=$(od -An -N1 -vto1 | tr -cd 0-7)

if [ -n "$byte" ]; then
  (printf "\\$byte"; cat) | gzip
else
  echo >&2 No input
fi

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.