Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Is there any way to redirect stdout and stderr via variable like adding command options in script?

For example I have a script:

#!/bin/bash -x
TEST=">/dev/null 2>&1"
OPT='-p -v'
mkdir $OPT 123/123/123 $TEST

I can see that OPT is replaced with -p without any problems and bash interprets it as option. But redirection interprets as directories name.

$ ./test.sh 
+ TEST='>/dev/null 2>&1'
+ OPT='-p -v'
+ mkdir -p -v 123/123/123 '>/dev/null' '2>&1'
mkdir: created directory `123/123'
mkdir: created directory `123/123/123'
mkdir: created directory `>/dev'
mkdir: created directory `>/dev/null'
mkdir: created directory `2>&1'

Is there any way to say bash, that $VAR is redirection, not a dirs names.

PS. May be I'm on wrong way, but I want to make optional verbose or non verbose output from my script. But I need some output even in non-verbose mode, therefore I can't just redirect whole stdout and stderr, only from some commands inside of my script.

share|improve this question
up vote 15 down vote accepted

Another solution could be the following:



exec 3>&1
exec 4>&2

if ((verbose)); then
  echo "verbose=1"
  echo "verbose=0"
  exec 1>/dev/null
  exec 2>/dev/null

echo "this should be seen if verbose"
echo "this should always be seen" 1>&3 2>&4

Then add 1>&3 2>&4 only to commands of which you want to see the output.

share|improve this answer
Great. This is exactly the thing I watched for. Thank you. – rush Jan 10 '12 at 13:45

It is not interpreting it as a "directory name", > is being quoted, so it being treated literally (more specifically, you are sending the string >dev/null 2>&1. Your only way of getting around this is using eval or spawning a new shell.

As for your "verbose" issue alluded to in your question, just do this instead:

if (( verbose )); then
    mkdir -v -p /foo
    mkdir -p /foo > /dev/null 2>&1
share|improve this answer

You have a lot of spaces in your variables, which will not be evaluated properly. You will want to use eval to set that up.

#!/bin/bash -x
TEST=">/dev/null 2>&1"
OPT='-p -v'
eval mkdir $OPT 123/123/123 $TEST

This will allow $OPT to be split into two arguments (-p and -v) instead of one (-p -v) and the same with $TEST. Also changed to use /dev/null since it is very unlikely that you will have a dev directory in the current directory.

share|improve this answer

The "how" has been well explained in other answers; I want to address the "why" the OP's code doesn't work.

The keynote is that output redirections are marked before variable expansion. Redirections are actually performed after variable expansion (hence why you can redirect output to a filename which is stored in a variable), but the shell identifies the redirections for later processing before variables are expanded.

In other words, once variables are expanded it is "too late" for a redirection character (< or >, etc.) to be considered, because the shell has already identified which parts of the command string it is going to handle as redirections.

For further reading, see steps 1 and 3 listed under:

share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.