Échapper des espaces dans un chemin distant lors de l'utilisation de rsync sur une connexion SSH distante

10

Lorsque vous utilisez SSH pour connecter rsync à un serveur distant, comment échappez-vous aux espaces et autres dans le chemin distant? Une simple barre oblique inverse échappe à l'espace pour l'invite bash locale, mais sur la machine distante, l'espace est alors lu comme une interruption du chemin, marquant ainsi la fin de ce chemin.

Donc, quand je fais rsync -avz /path/to/source/some\ dir/ [email protected]:/path/to/dest/some\ dir/ce qui se passe, c'est que le serveur distant lit cela comme juste /path/to/dest/some/et puisqu'il ne peut pas trouver cette destination à distance, car la destination réelle est "certains dir" plutôt que simplement "certains".

Si j'essaye la même commande et échappe à la barre oblique inverse et à l'espace pour dépasser l'invite bash locale et maintenir la barre oblique inverse pour le serveur distant (trois barres obliques inversées au total:) /path/to/dest/some\\\ dir/, cela envoie en effet la barre oblique inverse au serveur distant, mais au serveur distant interprète ensuite le chemin d'accès /path/to/dest/some\/plutôt que de /path/to/dest/some\ dir/supprimer l'espace et les caractères qui le suivent.

Si j'essaie de boucler le chemin avec des guillemets, il se comporte à peu près de la même manière, coupant efficacement le chemin dans l'espace. Donc, cela ne fonctionne que pour dépasser l'invite bash locale.

Au départ, j'utilisais un chemin qui contenait un segment "-" (espace-trait d'union-espace), et le serveur distant renvoyait une erreur rsync: on remote machine: -: unknown optionqui est à l'origine de cette tentative d'échapper à l'espace.

Alors, que dois-je faire pour que cela fonctionne correctement avec le serveur distant, sans avoir à supprimer les espaces ou autres caractères erronés comme les tirets du chemin distant?

purefusion
la source
1
Essayez des guillemets simples et doubles.
jftuga
Javier a également mentionné cela, et cela a fini par fonctionner, j'ai donc collé mon segment de code de travail dans une réponse à sa réponse.
purefusion
@purefusion Pensez à marquer la réponse de Grégory comme correcte. Le -srésout le problème sans qu'il soit nécessaire d'appliquer manuellement le double échappement.
m000

Réponses:

9

Sur la machine initiatrice, rsynccrée une ligne de commande qui appelle la cible rsync sur la machine distante, puis envoie cette ligne de commande en utilisant ssh .... comme une seule chaîne . Cette chaîne unique est passée au shell pour être analysée, divisée en arguments et exécutée rsync. Je n'ai aucune idée pourquoi est-ce fait, au lieu d'emballer les arguments (déjà fractionnés, développés et non cités) dans un conteneur binaire sûr vers le rsync distant.

Cela signifie que vos arguments seront analysés par deux coques différentes, citez et réévaluez en conséquence. Habituellement, j'encapsule chaque argument avec des guillemets doubles, puis l'expression entière sur des guillemets simples. parfois ce n'est pas suffisant, ou cela peut être compliqué si vous voulez que la même expression soit utilisée localement et à distance.

Dans ce cas, je définis généralement des liens logiciels avec des noms simples, sans espaces et entièrement ASCII, et je les utilise.

Javier
la source
8
Et le gagnant est ... guillemets simples + doubles! Peut-être que cela est différent sur chaque serveur, donc si les autres réponses ne fonctionnent pas pour certaines personnes, peut-être que celle-ci le fera. Voici le code réussi que j'ai utilisé sur le côté distant de la commande rsync:'[email protected]:"/path/to/dest/some\ dir/"'
purefusion
Maintenant, pose la question, pourquoi est-ce que ça marche (sur mon serveur), mais pas l'une des autres options (juste encapsuler le chemin entre guillemets doubles ou utiliser des barres obliques inverses)? J'utilise CentOS 5 si cela importe.
purefusion
Cela ne devrait pas être nécessaire. Comment le gérez-vous? L'utilisez-vous en utilisant evalou via un appel à une fonction peut-être?
Mikel
Vous n'utilisez pas de guillemets simples et doubles. Vous utilisez des guillemets simples, des guillemets doubles et des échappements antislash. TROIS niveaux de cotation. Cela ne devrait pas être nécessaire. Je demande à nouveau: comment le dirigez-vous ?
Mikel
@Javier "Je n'ai aucune idée pourquoi est-ce fait". Vraisemblablement pour que l'expansion de tilde fonctionne.
Mikel
2

Vous étiez sur la bonne voie lorsque vous avez dit:

Si j'essaye la même commande et échappe à la barre oblique inverse et à l'espace pour dépasser l'invite bash locale et maintenir la barre oblique inverse pour le serveur distant

Voici un moyen que je trouve le plus facile à faire:

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

et ça marche aussi.

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

Pouvez-vous publier la sortie exacte et les erreurs que vous voyez?

Pouvez-vous remplacer des rsyncdeux côtés un script wrapper?

$ 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

Ensuite, exécutez à nouveau votre rsync, et cela devrait prouver que cette façon de s'échapper fonctionne, par exemple

Côté client:

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

Du côté serveur:

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

Dans l'exemple ci-dessus, le fait que le 4ème argument sur le serveur ( dir with spaces) se trouve sur une seule ligne indique que la citation fonctionne correctement.

Si cela n'aide pas, essayez de relancer rsync -v, ou rsync -vv, ou rsync -vvv. Il vous donnera des informations de débogage supplémentaires.

Deux autres suggestions idiotes:

  • l'autre serveur est-il un serveur Linux, et quel est votre shell par défaut là-bas?
    • peut-être qu'il étend les noms de fichiers différemment de ce que vous attendez
  • avez-vous oublié d'ajouter l' option -aou -r?
    • Je ne peux pas dire sans voir ta sortie
Mikel
la source
Comme mentionné dans les détails de la question, j'ai effectivement essayé vos deux premières méthodes. Peut-être qu'ils ne fonctionnent tout simplement pas sur mon serveur. Je n'avais pas non plus envie de jouer avec les scripts wrapper. J'essaie de ne pas pirater le / usr / bin / ... En tout cas, une autre façon plus spécifique de citer a bien fonctionné pour moi, alors c'est peut-être juste mon serveur qui agit de cette façon. Vos suggestions peuvent toujours être viables pour les personnes sur d'autres serveurs, ou ceux qui n'exécutent pas CentOS, si le système d'exploitation fait partie du problème après tout.
purefusion
Alors, comment l'avez-vous cité pour le faire fonctionner?
Mikel
Vous omettez certains détails essentiels. Veuillez publier l'intégralité de la commande que vous exécutez.
Mikel
2

La réponse de point:

Utilisez -s (protect args) et mettez votre chemin entre guillemets:

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

Fonctionne avec les deux espaces ou tirets.

Grégory Boddin
la source
Merci! Il s'agit d'une solution appropriée, plutôt que d'une solution de contournement.
m000
-2

Vous pouvez simplement mettre votre chemin entre guillemets.

atx
la source
1
Comme vous l'avez peut-être vu dans les détails de la question, j'ai en effet déjà essayé cela. Cependant, une autre réponse a suggéré l'utilisation de devis spécifique, et cela a fini par fonctionner. :)
purefusion
Vous avez besoin des DEUX guillemets et des barres obliques inverses.
Sridhar Sarnobat