傳遞包含空格和括號的路徑的問題
我使用 Thunar 文件資源管理器並將路徑名和文件名傳遞給腳本音頻播放。audioplay 通過播放歌曲的 ssh 在我的 android 上執行播放命令。
音頻播放腳本::
cat audioplay
if [ $# -eq 1 ] ; then echo " Playing..." "$@" sshpass -p $passwd ssh root@192.168.43.10 -p $port play "$@" else echo " No Input audio file." fi
在我的安卓上播放腳本 ::
cat play
#!/data/bin/bash # Avoid linker errors due to libOpenSLES.so: echo "File ::" "$@" LD_LIBRARY_PATH= exec /data/bin/blob/play-audio "$@"
問題是路徑沒有正確傳遞以通過 ssh 播放命令。具有多個空格的路徑變為單個空格,並且括號會產生語法錯誤。
例子 :
對於
18. Warriors.flac
存在於的文件/sdcard/Music/Imagine Dragons - Smoke Mirrors -Deluxe Edition-2015
發送到音頻播放的路徑是正確的 ::
/sdcard/Music/Imagine Dragons - Smoke Mirrors -Deluxe Edition-2015/18. Warriors.flac
但是play腳本接收到的路徑錯誤 ::
/sdcard/Music/Imagine Dragons - Smoke Mirrors -Deluxe Edition-2015/18. Warriors.flac
多空格變成單空格。為什麼 ?然後主二進製文件只獲取到第一個空間的
play-audio
路徑。/sdcard/Music/Imagine
範例 2::
我嘗試使用帶有括號的文件 ::
44. Go Tell Aunt Rhody -Resident Evil- (Short Version).flac
音頻播放腳本收到的路徑是正確的 ::/sdcard/Music/44. Go Tell Aunt Rhody -Resident Evil- (Short Version).flac
但我收到此錯誤 ::sh: syntax error: '(' unexpected
我嘗試通過
$@
$*
"$@"
and"$*"
。但他們都沒有為我工作。
再次引用:
if [ "$#" -eq 1 ] ; then echo " Playing..." "$1" sshpass -p "$passwd" ssh root@192.168.43.10 -p "$port" "play '$1'" else echo " No Input audio file." fi
問題是第一層引號,
"$@"
當你執行sshpass
命令時被擴展。因此,當您登錄時,啟動遠端 shell 並執行play
,您有一個未加引號的字元串,因此您的腳本在空白處阻塞。通過將它包含在第二層引號中,您可以確保它被引用傳遞給遠端命令。假設 i) 遠端機器正在執行
sh
或bash
類似的 shell 並且 ii) 您的文件名不包含單引號,這應該可以工作。為了使其真正健壯,請參閱如何在不知道遠端使用者的登錄 shell 的情況下通過 ssh 執行任意簡單命令?.為了在語法中正確引用任意字元串(甚至是任意字元串列表,以便您可以將多個參數傳遞給
play
)sh
,我們可以使用shquote()
此處提到的函式:shquote() { LC_ALL=C awk -v q=\' -v b='\\' ' BEGIN{ for (i=1; i<ARGC; i++) { gsub(q, q b q q, ARGV[i]) printf "%s ", q ARGV[i] q } print "" exit }' "$@" } if [ "$#" -ge 1 ] ; then echo " Playing..." "$@" sshpass -p "$passwd" ssh root@192.168.43.10 -p "$port" "play $(shquote "$@")" else echo " No Input audio file." fi
它會引用哪個
Sgt. Pepper's lonely hearts club band.flac
是'Sgt. Pepper'\''s lonely hearts club band.mp3'
正確的sh
(而evil';reboot;: '.flac
不是'evil'\'';reboot;: '\''.flac'
重新啟動遠端機器(你必須將該play
命令執行為root
?))。