Redirecting standard out to /dev/null goes to file "/dev/null" instead

I apologize if this question has been answered else where or is too elementary.

I ran across a KSH script (long unimportant story) that does this:

if [ blahblah ] ; then
   CAS_SRC_LOG="/var/log/cas_src.log 2>&1"
else
   CAS_SRC_LOG="/dev/null 2>&1"
fi

then does this:

    /usr/bin/echo "heartbeat: `/usr/bin/date` " >> $CAS_SRC_LOG

In other words, based on some condition, the standard output destination is set to a either a file or to null. That was the intent.

In actuality, instead of going to null, the output goes to a file /dev/"null 2>&1"

-rw-r--r--    1 root     system     76774847 Feb 13 17:07 null 2>&1

My question is, what are the substitution and command line parsing rules? Why didn't the built command line string get parsed as expected?

Thanks
John Morrison

Because the shell only substitutes once. after it's done substituting in the text from the string, it won't go back and see that it was actually meant as a redirection. To do that kind of double-think, you'd have to feed it into eval.

1 Like

This should do the job

if [ blahblah ] ; then
  CAS_SRC_LOG="/var/log/cas_src.log"
else
  CAS_SRC_LOG="/dev/null"
fi

/usr/bin/echo "heartbeat: `/usr/bin/date` " >> $CAS_SRC_LOG 2>&1
1 Like

Thank you chihung for the fix.

So let me see if I understand this. I need to play tokenizer in my head to see this.

The parser sees the redirect token and sees that it is followed by a substitution string instead of something else like a directory path. Tokenizing on white-space (with parphrasing) it sees
... <stdout-redirect-append> <substitution-string>
instead of
... <stdout-redirect-append> <file-path> <stderr-redirect> <to-whereever-stdout-goes>

the <substitution-string> is internally processed as a <file-path> and since most characters, including spaces, can be in file names, the file name is "null 2>&1".

Subtle. A second parsing, after all string substitution would have reworked it, hence "eval".

Did I kinda get this right?

Thanks
John Morrison

It's not subtle, it's so unsubtle the human brain doesn't expect it :stuck_out_tongue:

It processes everything at the same time, in one whack. It has to get things out of the variable to consider them as shell statements -- and by the time it's done that, it's already done, so doesn't bother. Removing text from a variable is a processing step. To reprocess it again and consider it a shell statement would be another step, and it only does one step.

This is also a security feature, preventing someone from causing havoc just by inputting the raw text `rm -Rf /` and having it executed whenever any substitution happens.

This is also what makes eval so dangerous -- it will execute commands from arbitrary text. Use it with caution. Or better yet, don't use it at all.

Just FYI -

This is a known bug in certain versions of IBM Systems Director (aka CAS AGENT). Apparently it gets automatically installed on AIX 6.1 TL7. Here's a link to a blog (not mine) about how they fixed the issue (pretty much the same as suggested by chihung).

edit - I can't post URLs yet, but if you google "CAS AGENT BUG DEV NULL" it should be the first link.