0

I'm trying to Preserve Interpretation in Bash Variable.

Example

when I run the following line at command prompt.

rm aaa 2>> error_file ; echo '<br><br>' >> error_file

I get the following (which is what I want):

rm: cannot remove `aaa': No such file or directory

If I put the error handling code in a variable it blows-up.

ERROR_HAN="2>> error_file ; echo '<br><br>' >> error_file"
rm aaa $ERROR_HAN
rm: cannot remove `"2>>"': No such file or directory

I have tried quoting a number of ways but no luck. I can't seem to Preserve Interpretation for the 2>> portion of the variable.

user000001
  • 32,226
  • 12
  • 81
  • 108
Mike T
  • 93
  • 1
  • 2
  • 13

3 Answers3

0

Use eval:

eval rm aaa ${ERROR_HAN}
devnull
  • 118,548
  • 33
  • 236
  • 227
  • Thank you, seems to work fine. Not sure why konsolebox feels it's unsafe – Mike T Sep 04 '13 at 14:45
  • This doesn't just re-evaluate the contents of ${ERROR_HAN}, it re-evaluates the entire command line, leading to many confusing problems like needing do double-escape special characters etc. Also, if any part of the command is dynamically-generated (e.g. the filename), if it contains shell metacharacters they can be misinterpreted in confusing and/or dangerous ways. If you're willing to put something (like `eval`) at the beginning of the command (not just at the end), it'll be better to use a wrapper function instead. – Gordon Davisson Sep 04 '13 at 17:37
0

Don't put the command in a variable. Use a function instead:

rm_error() {
    rm "$@" 2>> error_file 
    echo '<br><br>' >> error_file
}

rm_error file1 file2 file3

See also: BashFAQ/050: I'm trying to put a command in a variable, but the complex cases always fail!

user000001
  • 32,226
  • 12
  • 81
  • 108
  • Thank you, I'm trying to create a variable that I can attach to the end of each command line in a daily batch job so that each command will either execute or write off the specific error to a file. – Mike T Sep 04 '13 at 14:47
  • @MikeT You can still do it from the command line. Just add the function definition in your `.bashrc` (or similar), and next time you open a terminal the `rm_error` command will be available – user000001 Sep 04 '13 at 14:52
  • Thank you, but I'm trying to have a function that I can append to the end of a number of different commands. So that if any of the commands throw an error the function will catch it. – Mike T Sep 04 '13 at 16:32
0

You'll to use eval for that which is unsafe.

Better redirect it on a block, and use process substitution:

{
    rm aaa
    # ... other commands
} 2> >(
    while read -r LINE; do
        echo "$LINE"
        echo '<br><br>'
    done >> error_file
)

Another way which would write <br><br> only once at the end:

{
    rm aaa
    # ... other commands
} 2> >(
    if read -r LINE; then
        while
            echo "$LINE"
            read -r LINE
        do
            continue
        done
        echo '<br><br>'
    fi >> error_file
)

This one would write <br><br> even without an error, and only once at the end:

{
    rm aaa
    # ... other commands
} 2>> error_file
echo '<br><br>' >> error_file

Note if you're only using one command like rm, you don't have to place it inside a block, just rm aaa 2>> >( .... And I think you'll only need one line:

rm aaa 2>> >(read -r LINE && echo "$LINE"$'\n''<br><br>' >> error_file)

Another:

EFILE=/path/to/error_file
rm aaa 2> >(read -r LINE && echo "$LINE"$'\n''<br><br>' >> "$EFILE")

Command-specific function:

EFILE=/path/to/error_file

function log_error_to_file {
    read -r LINE && echo "$LINE"$'\n''<br><br>' >> "$EFILE"
}

rm aaa 2> >(log_error_to_file)
another_command 2> >(log_error_to_file)

Multiple lines:

function log_error_to_file {
    while read -r LINE; do
        echo "$LINE"
        echo '<br><br>'
    done >> error_file
}
konsolebox
  • 72,135
  • 12
  • 99
  • 105
  • Thank you, I'm trying to create a variable that I can attach to the end of each command line in a daily batch job so that each command will either execute or write off the specific error to a file – Mike T Sep 04 '13 at 14:48
  • @MikeT How about a function instead? See the last part of my update. – konsolebox Sep 04 '13 at 15:05
  • @MikeT The questions is how would every line be sent to error file? Should `

    ` be added to every end, or after every command only? e.g. one for `rm`, another for `another_command`, etc..
    – konsolebox Sep 04 '13 at 15:07
  • I tried the function and receive the following: $ ./test1 + EFILE=/tmp/reports_cron + rm aaa ++ log_error_to_file ++ read -r LINE + set +x $ ++ echo 'rm: cannot remove `aaa'\'': No such file or directory

    ' # works as it should but it hangs. # I'm adding the '

    ' at the end of each response so that when I html email it to me it's not all run together.
    – Mike T Sep 04 '13 at 15:52
  • Upon further review all of the code samples seem to work fine EXCEPT when I include set -x and set +x. Cannot say I ever seen that before. Thank you konsolebox !! – Mike T Sep 04 '13 at 16:48
  • @MikeT I don't think it's a good idea to base from `set -x` when you're on a non-interactive bash. Better just use a literal string for every output. I added another modification of the function which bases itself from one of the previous methods. If it solves your problem, please accept the answer thanks. – konsolebox Sep 04 '13 at 17:12