An escaping of the variable within bash script

前端 未结 3 973
慢半拍i
慢半拍i 2021-01-27 09:43

My bash script writes an another bash script using printf.

printf \"#!/bin/bash
HOME=${server}
file=gromacs*
file_name=\\$(basename \"\\${file}\")
date=\\$(date          


        
相关标签:
3条回答
  • 2021-01-27 10:04

    Try this

    date=\$(date +\"%%m_%%d_%%Y\")" 
    
    0 讨论(0)
  • 2021-01-27 10:12

    You have to escapes in printf with esscaps, e. g.:

    date=\$(date +"%%m_%%d_%%Y")
    

    should print date=\$(date +"%m_%d_%Y"). But you should avoid using printf, because you don't use it's capabilities. Instead you could cat the string to the file:

    cat > ${output}/collecter.sh <<'END'
    HOME=${server}
    ...
    done
    END
    

    This would allow you to avoid many escapes, and make the code more readable.

    0 讨论(0)
  • 2021-01-27 10:25

    Use a quoted heredoc.

    {
      ## print the header, and substitute our own value for HOME
      printf '#!/bin/bash\nHOME=%q\n' "$server"
      ## EVERYTHING BELOW HERE UNTIL THE EOF IS LITERAL
      cat <<'EOF'
    file=( gromacs* )
    (( ${#file[@]} == 1 )) && [[ -e $file ]] || {
      echo "ERROR: Exactly one file starting with 'gromacs' should exist" >&2
      exit 1
    }
    file_name=$(basename "${file}")
    date=$(date +"%m_%d_%Y")
    
    for sim in "$HOME"/* ; do
     if [[ -d $sim ]]; then
      simulation=$(basename "$sim")
      (cd "${sim}" && exec cp "$file" "${server}/${results}/${file_name}.${simulation}.${date}")
      echo "${file_name} from ${simulation} has been collected!"
     fi
    done
    EOF
    } >"${output}/collecter.sh"
    

    Note:

    • Inside a quoted heredoc (cat <<'EOF'), no substitutions are performed, so no escaping is needed. We're thus able to write our code exactly as we want it to exist in the generated file.
    • When generating code, use printf %q to escape values in such a way as to evaluate back to their original values. Otherwise, a variable containing $(rm -rf ~) could cause the given command to be run (if it were substituted inside literal single quotes, making the contents $(rm -rf ~)'$(rm -rf ~)' would escape them).
    • Glob expansions return a list of results; the proper data type in which to store their results is an array, not a string. Thus, file=( gromacs* ) makes the storage of the result in an array explicit, and the following code checks for both the case where we have more than one result, and the case where our result is the original glob expression (meaning no matches existed).
    • All expansions need to be quoted to prevent string-splitting. This means "$HOME"/*, not $HOME/* -- otherwise you'll have problems whenever a user has a home directory containing whitespace (and yes, this does happen -- consider Windows-derived platforms where you have /Users/Firstname Lastname, or sites where you've mounted a volume for home directories off same).
    • pushd and popd are an interactive extension, as opposed to a tool intended for writing scripts. Since spawning an external program (such as cp) involves a fork() operation, and any directory change inside a subshell terminates when that subshell does, you can avoid any need for them by spawning a subshell, cd'ing within that subshell, and then using the exec builtin to replace the subshell's PID with that of cp, thus preventing the fork that would otherwise have taken place to allow cp to be started in a separate process from the shell acting as its parent.
    0 讨论(0)
提交回复
热议问题