2013-06-02 16 views
6

Mam zestaw skryptów, których używam do pobierania plików przez FTP, a następnie usuwania ich z serwera.Bash - Wykonywanie poleceń SSH

Działa on następująco:

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 

Teraz $ dir może być "Plik", który działa dobrze.

Problem mam jest ze znaków specjalnych np:

  • "Jest to (a) plik"
  • Ten plik jest & rzeczy”

tendencję do błędu:

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' 

Nie mogę wymyślić, jak uciec, aby obie zmienne zostały ocenione i komenda trafia właściwie. Próbowałem różnych kombinacji znaków ewakuacyjnych, dosłowne cytaty, cytaty itp normalne

+2

Jak o 'rsync --remove-source-files' http://serverfault.com/a/363925/69736 . Dużo łatwiej! –

+0

Nie jest jasne, w jaki sposób 'dir' jest ustawiony na pojedynczy ciąg 'This is (a) file'. Powinien być ustawiony kolejno na 4 oddzielne ciągi: "To", "jest", "(a)" i "plik". Nie parsuj wyniku polecenia 'ls'; przełącz katalog i iteruj na glob (zobacz moją odpowiedź dla szczegółów). – chepner

Odpowiedz

17

Jeśli obie strony są za pomocą bash, można uciec argumenty za pomocą printf '%q ', np:

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

'printf' jest wykonywane tylko na lokalnym końcu, więc' bash' nie jest potrzebny na zdalnym hoście. – chepner

+5

'% q' ucieka zgodnie z regułami ucieczki Basha. Jeśli bash nie jest zdalną powłoką, nie ma gwarancji, że wartości te są prawidłowe. –

+0

Mogłabym zasugerować zacytowanie tej zamiany poleceń - oczywiście, efekty uboczne z dzielenia łańcuchów i globalnej ekspansji nie są gwarantowane, ale są na pewno możliwe. –

1

trzeba zacytować całe wyrażenie ssh [email protected] "command":

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

To spowodowało, że zmienna oceniana jest na zdalnym końcu, a nie lokalny – Dan

+0

O, widzę. Aktualizuję więc odpowiedź bez znaku "$". Teraz powinno działać. – fedorqui

+0

To nadal powodowało błąd – Dan

0

Jestem zdezorientowany, ponieważ Twój kod jako pisemne prace dla mnie:

> 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 

Do debugowania, użyj set -vx u góry skryptu, aby zobaczyć, co się dzieje.

+1

spróbuj z 'dir =" nathan's crew.txt "' –

+0

@Will, masz mnie na tym, więc twoja odpowiedź jest zdecydowanie lepsza niż moja, ale wciąż jestem zdezorientowany co do tego, dlaczego OP miał problemy, które on stwierdził z skrypt, który opublikował. –

+1

Rzeczywisty problem wynika ze sposobu, w jaki polecenia zdalne są przekazywane przez SSH: Wszystkie argumenty są połączone i przekazywane do zdalnej powłoki jako pojedynczy ciąg - więc te podwójne cudzysłowy w przykładzie oryginalnego wpisu są w rzeczywistości tylko po to, aby utworzyć pojedyncze cudzysłowy istnieją na zdalnym końcu. –

0

Propozycja Palmer dotycząca używania printf jest świetna, ale wydaje mi się, że bardziej sensowne jest umieszczanie literalnych części w formacie printf.

ten sposób, multi-command jeden wkładki są bardziej intuicyjne, aby napisać:

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