2

I have script that prints out few lines of text. This text is used as configuration by other process.

When I normally run program I redirect standard output to file which is fine:

./generateConfig.sh > normal.cfg

But the problem is that normal.cfg is really constant and I would like to give user a choice to print to file or on the screen by providing additional parameter (like -o, without parameter arguments).

if the script content is:

#!/bin/bash
echo "8.8.8.8"

How would I parametrize output so that depending on args it will print out to file or stdout?

This does not seem to work:

#!/bin/bash
output="/dev/stdout"
if [ $# -gt 0 ]; then
  output="normal.cfg"
fi
echo "8.8.8.8" > $output
3
  • 1
    Your attempt seems to be correct, thought. It should work. What happens when you run it?
    – muru
    Feb 25 '16 at 12:58
  • 1
    @muru, on Linux, echo > /dev/stdout would reopen the file stdout goes to from scratch. For a regular file, that would overwrite it. For a socket, that would fail. (it could also be affected by the way shells perform redirection (like if they move fd 1 to something else before opening /dev/stdout). Feb 25 '16 at 13:31
  • Related: Conditional pipeline Feb 25 '16 at 13:32
3

You can redirect the output of the whole script using exec.

#! /bin/bash

if [[ $1 = -o ]]
then
    exec > "$2"
fi

echo "8.8.8.8"

Now, if you run the script with -o foo, the output will be in the file foo.

$ ./foo.sh 
8.8.8.8
$ ./foo.sh -o bar
$ cat bar
8.8.8.8
1
  • Thanks I was not aware of exec command. Thanks for explanation
    – Kamil
    Feb 25 '16 at 13:30
2

Several approaches:

A function

 #! /bin/sh -
 [ "$#" -gt 0 ] && redir=true || redir=false
 redir() if "$redir"; then "$@" > normal.cfg; else "$@"; fi

 redir echo 8.8.8.8

An alias:

 #! /bin/sh -
 [ -z "$BASH_VERSION" ] || shopt -s expand_aliases

 [ "$#" -gt 0 ] && alias redir='>normal.cfg' || alias redir=

 redir echo 8.8.8.8

(won't work with posh which disabled aliases, or if sourced (with the . command) in AT&T implementations of ksh).

A dedicated file descriptor:

 #! /bin/sh -
 [ "$#" -gt 0 ] && exec 3> normal.cfg || exec 3>&1

 echo 8.8.8.8 >&3

(beware that apart from ksh93, not many shells set the close-on-exec flag on that fd 3, so you may want to close it for commands you execute by hand)

4
  • I'm curious: why would you use sh as for the shebang in the alias examlpe?
    – muru
    Feb 25 '16 at 14:19
  • @muru, because that would work with most sh and all systems have a sh, while not so many have bash. For those unlucky enough to have bash as their sh, I add the workaround for bash that doesn't expand aliases in non-interactive shells. Feb 25 '16 at 14:22
  • So aliases are on by default in noninteractive ksh, zsh, dash, etc.?
    – muru
    Feb 25 '16 at 14:31
  • @muru, yes. There are some contexts where some aliases are not expanded in some shells (like in sh -c '...' or sourced files), but the above should work on most systems. Some shells even allowed exporting aliases. POSIX leaves it unspecified whether aliases are expanded or not in non-interactive shells. Feb 25 '16 at 14:46
-1

Try with:

#!/bin/bash
output="normal.cfg"
if [ $# -gt 0 ]; 
 then
  echo "8.8.8.8" > $output
 else
  echo "8.8.8.8"
fi

If you want to do something more complex, you may try tee command: see example here.

1
  • Appreciate but I am looking for something more advanced. The script above is just example, in fact it's more complex.
    – Kamil
    Feb 25 '16 at 13:08

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.