我已經寫了一個bash日誌庫來實現一些我公司目前使用的複雜腳本。在進行日誌調用時,我一直在提供調用腳本的腳本文件名($ {BASH_SOURCE})和行號($ {LINENO})。但是,我不想依靠用戶或實現腳本來傳遞這兩個變量作爲參數。如果這是C/C++,我只需創建一個宏,它將參數列表中的「__FILE__」和「__LINE__」預先設置好。Bash參數報價和評估
我終於能夠得到這部分工作。這裏有一些非常簡單的摘要作爲一個概念證明:
這裏的日誌庫:
# log.sh
LOG="eval _log \${BASH_SOURCE} \${LINENO}"
_log() {
_BASH_SOURCE=`basename "${1}"` && shift
_LINENO=${1} && shift
echo "(${_BASH_SOURCE}:${_LINENO}) [email protected]"
}
而且一個執行測試腳本:
# MyTest.sh
. ./log.sh
${LOG} "This is a log message"
# (test.sh:5) This is a log message
這工作得很好(和我很高興能夠讓它在第一時間工作)。然而,這有一個明顯的問題:引號與eval之間的相互作用。如果我撥打電話:
${LOG} "I'm thrilled that I got this working"
# ./test.sh: eval: line 5: unexected EOF while looking for matching `''
# ./test.sh: eval: line 6: syntax error: unexpected end of file
現在,我相信我明白爲什麼會發生這種情況。引用的參數在傳遞給eval時保持不變,但在此時,內容將按照原樣放置到生成的命令字符串中。我知道我可以通過做一些逃避來解決這個問題。然而,我真的不想強制執行腳本必須這樣做。在我實現這個「eval宏」功能之前,我讓用戶直接調用「_log」並允許他們可選地傳入「$ {LINENO}」。通過這個實現,上面的失敗調用(只有引用的句子)工作得很好。
在最基本的層面上,我真正想要的是一個腳本,能夠調用[日誌功能/宏]「字符串登錄特殊characers」和具有生成的日誌消息包含文件名和行調用腳本的編號,然後是日誌消息。如果可能的話,我會認爲我非常接近,但是如果我忽略了一些需要採用不同方法的東西,我也會這樣認爲。我不能強迫用戶轉移他們的所有消息,因爲這可能會導致他們不使用這個庫。這是一個問題,如果我找不到解決方案,我可能會回到舊的功能(需要$ {LINENO}作爲函數參數傳遞 - 這是非常不容易侵入的)。
TLDR:有什麼辦法讓eval尊重引用參數中的特殊字符,而不必轉義它們嗎?
如果您使用bash特定結構,則不應將您的日誌記錄腳本命名爲「log.sh」。它應該是「log.bash」。 –
@WilliamPursell - 我做了一些搜索,找不到任何關於shell腳本命名約定的標準。事實上,大多數人似乎完全沒有後綴。說實話,我從來沒有見過除'\ *。sh'之外的東西(或者沒有擴展名/後綴的腳本)。在所有的實際應用中,它不應該有任何影響,對吧?解釋器或者從腳本的第一行中拉出來,或者使用當前的shell。它似乎基本上歸結爲個人偏好。但是,也許「\ *。sh」可能暗示給用戶腳本使用「sh」。 – LousyG
唯一的實際影響是如果開發人員使用不同的shell使用你的函數。用'* .sh'這個名字,開發人員會合理地認爲你的庫可以用zsh腳本來源。 –