2013-06-02 79 views
6

我有一組腳本用於通過FTP下載文件,然後將它們從服務器中刪除。Bash - 轉義SSH命令

其工作原理如下:

for dir in `ls /volume1/auto_downloads/sync-complete` 
do 
if [ "x$dir" != *"x"* ] 
then 
echo "DIR: $dir" 

echo "Moving out of complete" 
     # Soft delete from server so they don't get downloaded again 
     ssh [email protected] mv -v "'/home/dan/Downloads/complete/$dir'" /home/dan/Downloads/downloaded 

現在$ DIR可能是 「這是一個文件」,它工作正常。

我遇到的問題是有特殊字符,例如:

  • 「這是(a)提交」
  • 這是一個文件&東西」

往往錯誤:

bash: -c: line 0: syntax error near unexpected token `(' 
bash: -c: line 0: `mv -v '/home/dan/Downloads/complete/This is (a) file' /home/dan/Downloads/downloaded' 

我不知道如何逃避它,所以變量得到評估和命令正確地轉義。我試過的轉義字符的各種組合,文字的報價,報價正常,等

+2

怎麼樣'rsync的--remove-源files' http://serverfault.com/a/363925/69736 。更容易! –

+0

目前還不清楚如何將'dir'設置爲單個字符串'This is(a)file'。它應該先後設置爲4個單獨的字符串'This','是','(a)'和'file'。不要分析'ls'的輸出;切換目錄並迭代glob(請參閱我的答案以獲取詳細信息)。 – chepner

回答

17

如果雙方都使用bash,您可以使用轉義參數printf '%q ',如:

ssh [email protected] "$(printf '%q ' mv -v "/home/dan/Downloads/complete/$dir" /home/dan/Downloads/downloaded)" 
+1

'printf'只在本地執行,所以在遠程主機上不需要'bash'。 – chepner

+5

'%q'根據Bash的逃避規則逃跑。如果bash不是遠程shell,則不能保證轉義是有效的。 –

+0

我傾向於建議引用命令替換 - 當然,不能保證來自字符串分割和glob擴展的副作用,但它們當然是可能的。 –

1

您需要引用整個表達式ssh [email protected] "command"

ssh [email protected] "mv -v /home/dan/Downloads/complete/$dir /home/dan/Downloads/downloaded" 
+0

這導致在遠端評估變量,而不是當地的 – Dan

+0

哦,我明白了。所以我更新了我的答案,沒有'$'轉義。它現在應該工作。 – fedorqui

+0

這仍然導致錯誤 – Dan

0

我很困惑,因爲你的代碼爲我寫的作品:

> dir='foo & bar (and) baz' 
> ssh host mv -v "'/home/dan/Downloads/complete/$dir'" /home/dan/Downloads/downloaded 
mv: cannot stat `/home/dan/Downloads/complete/foo & bar (and) baz': No such file or directory 

要進行調試,請在腳本頂部使用set -vx以查看發生了什麼。

+1

嘗試用'dir =「nathan的crew.txt」' –

+0

@你會得到我的那一個,所以你的答案肯定比我的好,但我仍然困惑爲什麼OP有他遇到的問題他發佈的腳本。 –

+1

實際的問題來自遠程命令通過SSH傳遞的方式:所有參數連接在一起並作爲單個字符串傳遞到遠程shell - 因此原始帖子示例中的雙引號實際上僅用於使單引號存在於遠端。 –

0

威爾帕爾默的使用printf的建議很好,但我認爲將文字部分放在printf的格式中更有意義。

這樣一來,多命令的單行是更直觀地寫:

ssh [email protected] "$(printf 'mkdir -p -- %q && cd -- "$_" && tar -zx' "$DIR")"