4

I'm trying to use eval command to eval a comment -- I'm not sure if this is the right way to do it. Example:

i=?? (What I want here is either a #, to comment what's after, or blank)

somecommand arg1 arg2 $(eval $i) >> file

So based on the $i value it has to be either:

somecommand arg1 arg2 # >> file as of "Don't print to file"

or

somecommand arg1 arg2 >> file as of "Print to file"

An example script for more clarity:

i=true

somecommand arg1 arg2 >> file1
[some code]
somecommand arg1 arg2 >> file2
[some code]
somecommand arg1 arg2 >> file3
[some code]
And so on...

I want it to print the output to the files only if $i it true; or, as I tried at first, to eval the $i to be a comment and comment the 'output to file' piece of code.

I asked because I think there is a more elegant way than doing something like this:

if $i
then
   somecommand arg1 arg2 >> file3
else
   somecommand arg1 arg2
fi
Jeff Schaller
  • 66,199
  • 35
  • 114
  • 250
Raywando
  • 427
  • 1
  • 4
  • 7
  • 3
    Hi and welcome. Instead of asking about a specific solution to your problem, I suggest you instead ask about the problem you're trying to solve. It sounds like that problem is: _How do I conditionally redirect output to a file?_ Is that correct? – Andy Dalton Jul 18 '20 at 15:06
  • 3
    ... [Elegant solution to echo to either stdout or file in bash](https://unix.stackexchange.com/questions/336224/elegant-solution-to-echo-to-either-stdout-or-file-in-bash) – steeldriver Jul 18 '20 at 15:08
  • Thanks @steeldriver , but that's, not the answer I'm looking for, I want it to print based on a variable, keep in mind there are a lot of files to print to, not only one file – Raywando Jul 18 '20 at 15:11
  • 2
    The answer @steeldriver referenced enables your use case. – Andy Dalton Jul 18 '20 at 15:13
  • 2
    `eval` is a last resort approach, especially for non-experts. So you should explain clearly why you think the linked answer is not suitable for you. – Hauke Laging Jul 18 '20 at 15:15
  • I have edited the post, i hope the example made it clear @HaukeLaging – Raywando Jul 18 '20 at 15:25
  • How portable do you need this to be ? Are you working only on Linux or do you intend to target other operating systems, like BSD , MAC OS, AIX ? – Sergiy Kolodyazhnyy Jul 18 '20 at 21:00
  • And it's still somewhat unclear what you're trying to achieve. I noticed you're using `somecommand` multiple times in your example, so this is same command , just writing to different files each time ? Or `somecommand` in `somecommand arg1 arg2 >> file1` is different from `somecommand` in `somecommand arg1 arg2 >> file2` ? – Sergiy Kolodyazhnyy Jul 18 '20 at 21:08

1 Answers1

12

You could always do:

unset -v log
# or
log=true
([ -z "$log" ] || exec >> file1; somecommand arg1 arg2)
([ -z "$log" ] || exec >> file2; somecommand arg1 arg2)

Or:

if [ -n "$log" ]; then
  exec 3>> file1 4>> file2
else
  exec 3>&1 4>&1
fi
somecommand arg1 arg2 >&3
somecommand arg1 arg2 >&4

Or:

log() {
  local output="$1"; shift
  if [ -n "$output" ]; then
    "$@" >> "$output"
  else
    "$@" 
  fi
}

log "${log+file1}" somecommand arg1 arg2
log "${log+file2}" somecommand arg1 arg2

Or (make sure the data passed to eval is not dynamic to avoid code injection vulnerabilities, hence the use of single quotes below inside which no expansion occurs):

eval ${log+'>> file1'} 'somecommand arg1 arg2'
eval ${log+'>> file2'} 'somecommand arg1 arg2'

With zsh:

if (($+log)); then
  alias -g 'log?=>>'
else
  alias -g 'log?=#'
fi

somecommand arg1 arg2 log? file1
somecommand arg1 arg2 log? file2

Or even (if you don't intend to use >> for anything other than that kind of conditional logging):

(($+log)) || alias -g '>>=#'

somecommand arg1 arg2 >> file1
somecommand arg1 arg2 >> file2

bash doesn't have alias -g, doesn't let you alias things like >>, but you could use simple aliases if you move the redirection to the start:

shopt -s expand_aliases
skip_one() { shift; "$@"; }
if [[ -v log ]]; then
  alias 'log?=>>'
else
  alias 'log?=skip_one'
fi

log? file1 somecommand arg1 arg2
log? file2 somecommand arg1 arg2
Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501