2017-08-21 21 views
0

我的bash腳本使用printf編寫了另一個bash腳本。bash腳本中的變量轉義

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


for sim in \${HOME}/* ; do 
if [[ -d \$sim ]]; then 
    simulation=$(basename "\$sim") 
    pushd \${sim} 
    cp \$file \${server}/\${results}/\${file_name}.\${simulation}.\${date} 
    echo "\${file_name}\ from\ \${simulation}\ has\ been\ collected!" 
    popd 
fi 
done" > ${output}/collecter.sh 

在這裏有日期變量

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

內的元素的escappiong一個問題,下面的部分沒有正常工作

"\%m_\%d_\%Y" 

它會導致不完整的一個新的bash腳本由printf生成。

它應該如何修復?

謝謝!

+0

您沒有在第一時間逃生''%。 –

回答

0

試試這個

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

你必須printf以逃脫與esscaps,E。 g .:

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

應打印date=\$(date +"%m_%d_%Y")。但是你應該避免使用printf,因爲你不使用它的功能。相反,您可以將字符串捕獲到文件中:

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

這將允許您避免許多轉義,並使代碼更具可讀性。

+1

你可以實現與'printf的 '%s' 的 「...」> $ {}輸出/ collecter.sh'同樣的效果。 – melpomene

+0

但是有什麼優勢? – clemens

+1

'<< END',與'END'無引號,仍然執行定界符內部擴展。因此,仍然需要很多逃生。它需要是「<< END」或「<< END''才能使內容完全成爲文字。 –

3

使用引用的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" 

注:

  • 裏面一個引號定界符(cat <<'EOF'),沒有換人執行,需要這樣沒有逃脫。因此,我們能夠完全按照我們希望它存在於生成的文件中編寫我們的代碼。
  • 當生成代碼時,請使用printf %q來轉義值,以便返回到原始值。否則,包含$(rm -rf ~)的變量可能會導致運行給定的命令(如果它在文字單引號內被替換,則使內容$(rm -rf ~)'$(rm -rf ~)'可以轉義它們)。
  • Glob擴展返回結果列表;在其中存儲結果的正確數據類型是一個數組,而不是一個字符串。因此,file=(gromacs*)使結果在數組中顯式存儲,下面的代碼檢查我們有多個結果的情況以及結果是原始glob表達式(意味着沒有匹配存在)的情況。
  • 所有擴展都需要引用以防止字符串拆分。這意味着"$HOME"/*,而不是$HOME/* - 否則,只要用戶的主目錄包含空格(並且是的,這確實發生了 - 考慮Windows衍生的平臺,您有/Users/Firstname Lastname或已安裝的站點主目錄的卷也一樣)。
  • pushdpopd是一個互動的延伸,而不是用於編寫腳本的工具。由於產卵外部程序(如cp)涉及一個叉()操作,和子外殼內部的任何目錄改變終止時子shell做,可避免任何需要他們通過產卵子外殼,cd「荷蘭國際集團即子外殼內,然後使用exec內置更換子shell的與的cp PID,從而防止否則將發生允許cp在從殼充當其父單獨的過程中開始fork
+0

錯誤是什麼? – wjandrea

+0

啊 - 不是一個錯誤,而是一個風格問題;那是「與作者意圖衝突」,而不是「造成傷害」。道歉。 –

+0

啊,好吧,對不起。我可以看出你的意思,以及你爲什麼會這樣做。 – wjandrea