J'essaie d'échapper au caractère d'espace pour un chemin dans Bash, mais ni en utilisant une barre oblique inverse ou guillemets fonctionne.
Script .sh:
ROOT="/home/hogar/Documents/files/"
FILE=${ROOT}"bdd.encrypted"
DESTINATION="/home/hogar/Ubuntu\ One/folder"
mv ${FILE} ${DESTINATION}
Après avoir exécuté le script (./file
) voici le résultat:
mv: target 'One/folder' is not a directory
Pourquoi la commande mv
divise-t-elle la chaîne et comment puis-je empêcher que cela se produise?
Vous développez la variable DESTINATION, si vous aviez echo
voici ce que vous obtiendriez:
echo ${DESTINATION}
/home/hogar/Ubuntu\ One/folder
Mais mv
ne comprend pas ceci:
mv ${FILE} ${DESTINATION}
mv: cannot move '/home/hogar/Documents/files/bdd.encrypted' to '/home/hogar/Ubuntu\\ One/folder': No such file or directory
(pour une raison quelconque, mon mv est plus verbeux)
Pour éviter cela, vous devez utiliser des guillemets à la place:
mv "${FILE}" "${DESTINATION}"
Si vous n'avez pas besoin d'extension (puisque vous étendez déjà avant), utilisez simplement "$..."
devrait suffire:
mv "$FILE" "$DESTINATION"
Votre étape pour préparer les variables est "assez proche" et fonctionnera, mais elle montre une faiblesse dans la compréhension (c'est pourquoi vous avez posté!)
L'affectation à DESTINATION ne doit être que l'une des deux suivantes:
DESTINATION="/home/hogar/Ubuntu One/folder"
ou
DESTINATION=/home/hogar/Ubuntu\ One/folder
Les guillemets doubles activent les guillemets (un formulaire qui a de la magie) et la barre oblique inverse est capable de citer un seul caractère qui le suit. Personnellement, je pense que le formulaire utilisant des guillemets doubles est préférable car visuellement c'est plus agréable.
Soit dit en passant, pour des raisons similaires, je ferais la tâche FILE comme:
FILE="${ROOT}bdd.encrypted"
ce qui montre l'occasion assez rare d'utiliser ${NAME}
au lieu de simplement $NAME
- pour séparer le nom de la variable de toute lettre suivante. En fait, si vous n'aviez pas de fin/sur la définition de ROOT, j'écrirais
FILE="$ROOT/bdd.encrypted"
qui a l'air encore mieux. Cela vous donnera également des avantages occasionnels dans lesquels je n'entrerai pas; disons simplement d'après mon expérience, les barres obliques de fin ont tendance à être plus indésirables que les bienvenues, et elles ne sont certainement pas nécessaires. (Cela a des conséquences en ce qui concerne les liens symboliques, mais c'est certainement trop de détails sur cette réponse déjà volumineuse).
Le nœud de votre problème se produit en fait à la commande mv, qui devrait être écrite comme
mv "$FILE" "$DESTINATION"
car de nos jours, on ne sait jamais quand une variable représentant un chemin aura des espaces dedans. Encore une fois, notez l'évitement des accolades pour une simple expansion variable.
La raison pour laquelle vous avez rencontré un problème est due au processus utilisé par le shell pour créer des lignes de commande. Si vous lisez attentivement le manuel de Shell, il dit essentiellement que les variables (et quelques autres choses) sont développées PUIS il va chercher des espaces. Bien sûr, il y a un peu plus de complexité dans le processus, mais c'est l'essentiel du problème pour vous.
Un autre point qui est lié et mérite d'être connu: la distinction entre $*
, $@
, "$*"
et "$@"
. Je vais donc en parler!
Si vous avez un script Shell qui peut être appelé comme:
foo -x "attached is the software" "please read the accompanying manual"
alors foo
verra -x
comme $1
, et les deux chaînes comme $2
et $3
(auquel vous devez accéder en tant que "$2"
et "$3"
pour des raisons évidentes). Si, cependant, vous souhaitez transmettre cet ensemble de paramètres à un autre script, les éléments suivants subiront un fractionnement horrible sur tous les espaces:
bar $*
et ce qui suit (qui était le seul moyen dans la version 0.X du Bourn Shell très original) fera passer tous les arguments en une seule chaîne (également FAUX)
bar "$*"
donc la syntaxe suivante a été ajoutée comme cas magique très spécial:
bar "$@"
qui cite délibérément les membres individuels de $*
en tant que chaînes complètes entre guillemets mais les garde séparées. Tout le monde est gagnant maintenant.
C'est un peu amusant de tester d'autres effets de $@
lorsqu'il n'est pas utilisé comme "$@"
mais vous découvrirez rapidement que ce n'est pas vraiment divertissant ... c'est simplement un cas spécial qui résout un problème majeur.
Tous les shells modernes décents qui prennent en charge les tableaux utilisent également @ dans un cas spécial:
${arr[*]}
"${arr[*]}"
"${arr[@]}"
où le premier souffrira de la division sur tous les espaces, conduisant à un nombre imprévisible de mots séparés, le second produira tous les membres du tableau dans une chaîne, et le troisième offrira très bien chaque membre du tableau en tant que chaîne individuelle non interrompue entre guillemets.
Prendre plaisir!
Oui, vous avez échappé à l'espace lorsque vous attribuez la valeur à $DESTINATION
,
Mais lorsque vous l'utilisez avec la commande mv, vous ne l'avez pas
mv ${FILE} ${DESTINATION}
Utilisez-le à la place:
mv "${FILE}" "${DESTINATION}"