Zmiana znaczenia spacji na zdalnej ścieżce podczas używania rsync przez zdalne połączenie SSH

10

Kiedy używasz SSH do łączenia rsync ze zdalnym serwerem, w jaki sposób unikasz spacji i tym podobnych na zdalnej ścieżce? Prosty ukośnik odwraca miejsce dla znaku zachęty lokalnego bash, ale na zdalnej maszynie przestrzeń jest następnie odczytywana jako przerwa na ścieżce, oznaczając w ten sposób koniec tej ścieżki.

Kiedy więc to robię rsync -avz /path/to/source/some\ dir/ [email protected]:/path/to/dest/some\ dir/, zdalny serwer odczytuje to jako słuszne /path/to/dest/some/i ponieważ nie może zdalnie znaleźć tego miejsca docelowego, ponieważ rzeczywistym miejscem docelowym jest „niektóre katalog”, a nie tylko „niektóre”.

Jeśli spróbuję wykonać to samo polecenie i uciec od ukośnika odwrotnego i miejsca, aby ominąć lokalny monit bash i zachować odwrotny ukośnik dla zdalnego serwera (łącznie trzy ukośniki odwrotne:) /path/to/dest/some\\\ dir/, to rzeczywiście wysyła odwrotny ukośnik do zdalnego serwera, ale zdalny serwer następnie interpretuje ścieżkę /path/to/dest/some\/raczej niż /path/to/dest/some\ dir/rozbija spację i znaki po niej.

Jeśli spróbuję zawinąć ścieżkę w cudzysłów, zachowuje się ona w ten sam sposób, skutecznie odcinając ścieżkę w przestrzeni. Więc to działa tylko, aby ominąć lokalny monit bash.

Początkowo korzystałem ze ścieżki, w której znajdował się segment „-” (spacja-myślnik-spacja), a serwer zdalny zwrócił błąd, rsync: on remote machine: -: unknown optionktóry w pierwszej kolejności zapoczątkował tę ucieczkę w przestrzeń.

Co więc muszę zrobić, aby działało to poprawnie ze zdalnym serwerem, bez konieczności usuwania spacji lub innych błędnych znaków, takich jak łączniki ze zdalnej ścieżki?

czysta fuzja
źródło
1
Wypróbuj zarówno pojedyncze, jak i podwójne cytaty.
jftuga
Javier również o tym wspomniał, ale ostatecznie zadziałało, więc wkleiłem mój działający fragment kodu w odpowiedzi na jego odpowiedź.
purefusion,
@purefusion Rozważ zaznaczenie odpowiedzi Grégory'ego poprawną. W -srozwiązuje problem bez konieczności zastosowania podwójnej ucieczki ręcznie.
m000

Odpowiedzi:

9

Na maszynie inicjującej rsyncbuduje wiersz poleceń, który wywołuje cel rsync na komputerze zdalnym, a następnie wysyła ten wiersz poleceń za pomocą ssh .... jako pojedynczego ciągu . Ten pojedynczy ciąg jest przekazywany do powłoki w celu przeanalizowania, podzielenia na argumenty i wykonania rsync. Nie mam pojęcia, dlaczego tak się dzieje, zamiast pakować (już podzielone, rozwinięte i niecytowane) argumenty w jakiś bezpieczny kontener binarny do zdalnego rsync.

Oznacza to, że argumenty będą przetwarzane przez dwóch różnych muszli, cytat i rekwotowaniu odpowiednio. Zazwyczaj każdy argument owijam podwójnymi cudzysłowami, a następnie całe wyrażenie na pojedyncze cudzysłowy. czasem to nie wystarczy lub może być skomplikowane, jeśli chcesz, aby to samo wyrażenie było używane lokalnie i zdalnie.

W takich przypadkach zwykle ustawiam niektóre miękkie linki z prostymi nazwami bez spacji i wyłącznie ASCII i używam ich.

Javier
źródło
8
Zwycięzcą jest ... pojedyncze + podwójne cytaty! Może jest inaczej na każdym serwerze, więc jeśli inne odpowiedzi nie działają dla niektórych osób, być może ta będzie. Oto udany kod, którego użyłem po drugiej stronie polecenia rsync:'[email protected]:"/path/to/dest/some\ dir/"'
purefusion
Teraz nasuwa się pytanie, dlaczego TO działa (na moim serwerze), ale nie ma żadnej z pozostałych opcji (po prostu zawijanie ścieżki w podwójne cudzysłowy lub używanie potrójnych odwrotnych ukośników)? Używam CentOS 5, jeśli to ma znaczenie.
purefusion,
To nie powinno być konieczne. Jak to działa? Czy uruchamiasz go za pomocą evallub może poprzez wywołanie funkcji?
Mikel
Nie używasz podwójnych cudzysłowów plus. Używasz pojedynczych cudzysłowów, podwójnych cudzysłowów i znaków odwrotnego ukośnika. TRZY poziomy cytowania. To powinno być niepotrzebne. Pytam ponownie: jak to robisz ?
Mikel
@Javier „Nie mam pojęcia, dlaczego tak się dzieje”. Przypuszczalnie po to, by rozszerzenie tyld działało.
Mikel
2

Byłeś na dobrej drodze, kiedy powiedziałeś:

Jeśli wypróbuję to samo polecenie i wyjdę z ukośnika odwrotnego i spacji, aby ominąć lokalny monit bash i zachować odwrotny ukośnik dla zdalnego serwera

Oto sposób, w jaki najłatwiej to zrobić:

rsync -av dir\ with\ spaces/ server.tld:"dir\ with\ spaces"

i tak też działa.

rsync -av dir\ with\ spaces/ server.tld:dir\\\ with\\\ spaces

Czy możesz opublikować dokładne dane wyjściowe i jakiekolwiek błędy, które widzisz?

Czy możesz zastąpić rsyncpo obu stronach skryptem opakowania?

$ sudo su -
# cd /usr/bin
# mv rsync rsync.real
# cat <<'EOF' >rsync
#!/bin/bash
logfile=/home/yourname/rsync.log
date >> "$logfile"
i=1
for arg in "$@"; do
    echo "arg $i: $arg" >> "$logfile"
    i=$((i+1))
done

rsync.real "$@"
EOF
# chmod +x rsync

Następnie uruchom ponownie rsync i powinno to udowodnić, że ten sposób ucieczki działa, np

Strona klienta:

Sun Feb 13 13:48:12 EST 2011
1: -av
2: dir with spaces/
3: server:dir\ with\ spaces

Po stronie serwera:

Sun Feb 13 13:48:13 EST 2011
1: --server
2: -vlogDtpre.iL
3: .
4: dir with spaces

W powyższym przykładzie fakt, że czwarty argument na serwerze ( dir with spaces) znajduje się w jednym wierszu, oznacza, że ​​cytowanie działa poprawnie.

Jeśli to nie pomoże, spróbuj ponownie uruchomić rsync -v, lub rsync -vv, lub rsync -vvv. Dostarczy dodatkowych informacji debugowania.

Dwie inne głupie sugestie:

  • czy drugi serwer to serwer Linux i jaka jest tam twoja domyślna powłoka?
    • może rozszerza nazwy plików inaczej niż się spodziewasz
  • zapomniałeś dodać opcję -alub -r?
    • Nie mogę powiedzieć, nie widząc twoich wyników
Mikel
źródło
Jak wspomniano w szczegółach pytania, rzeczywiście wypróbowałem obie pierwsze dwie metody. Być może po prostu nie działają na moim serwerze. Nie miałem też ochoty bawić się skryptami otoki. Staram się trzymać z dala od hakowania / usr / bin / ... W każdym razie inny bardziej konkretny sposób cytowania rzeczywiście zadziałał dla mnie, więc może to tylko mój serwer działa w ten sposób. Twoje sugestie mogą z pewnością być wykonalne dla osób na innych serwerach lub tych, które nie używają CentOS, jeśli mimo wszystko system operacyjny stanowi część problemu.
purefusion
Jak to zacytowałeś, żeby działało?
Mikel
Pomijasz niektóre istotne szczegóły. Proszę zamieścić w całości aktualne polecenie.
Mikel
2

Odpowiedź na pytanie:

Użyj -s (chroń argumenty) i umieść swoją ścieżkę w cudzysłowie:

rsync -savz user@server:"/my path with spaces/another dir/" "/my destination/"

Działa zarówno z odstępami, jak i myślnikami.

Grégory Boddin
źródło
Dzięki! Jest to właściwe rozwiązanie, a nie obejście.
m000
-2

Możesz po prostu zawrzeć swoją ścieżkę w cudzysłowie.

atx
źródło
1
Jak zapewne widzieliście w szczegółach pytania, rzeczywiście już tego próbowałem. Jednak inna odpowiedź sugerowała konkretne użycie cytatu, i to naprawdę skończyło się. :)
purefusion,
Potrzebujesz OBCYCH cytatów i ukośników odwrotnych.
Sridhar Sarnobat