web-dev-qa-db-fra.com

Problème avec l'entrée d'un simple script qui copie un fichier dans un autre répertoire

En tant que personne essayant d'apprendre bash, j'ai créé des scripts simples pour tester diverses commandes. Dans le script simple suivant, j'expérimente avec la commande de lecture.

#!/bin/bash
read -p "Enter a path to a file: " file_to_copy
cp $file_to_copy /tmp

Si l'utilisateur entre l'intégralité du chemin d'accès à un fichier de test, par exemple,/home/$ USER/test à l'invite, le script s'exécute comme prévu et crée une copie de "test" dans le répertoire/tmp. Cependant, si l'utilisateur entre le raccourci ~/test, le terminal renvoie l'erreur cp: impossible de stat '~/test': aucun fichier ou répertoire de ce type. Pourquoi la commande cp ne parvient-elle pas à trouver une représentation équivalente du chemin du fichier une fois entré?

Si j'entre indépendamment dans le terminal:

cp ~/test /tmp

le fichier de test est copié sans incident, il s'agit donc probablement d'une nuance d'affectation de variable que je me suis trompée, mais que je ne peux pas comprendre.

Merci.

4
mike3759

Ce qui se passe, c’est que vous demandez littéralement à Shell de trouver ~/test à partir du répertoire dans lequel le script se trouve actuellement. En d’autres termes, si vous exécutez à partir de /home/$USER, il recherchera le fichier test in sous-répertoire nommé ~, pas le développement /home/$USER/test.

Ce que vous pouvez utiliser, c’est l’évaluation intégrée de bash, qui prend tous les arguments, les regroupe en une seule commande et laisse le shell l’exécuter. Maintenant, Shell développera ~.

xieerqi:
$ ./copyScript.sh                                                                                                       
Enter a path to a file: ~/test
Entered /home/xieerqi/test

xieerqi:
$ ls -l /tmp/test
-rw-rw-r-- 1 xieerqi xieerqi 0 Dec 21 01:14 /tmp/test

xieerqi:
$ cat copyScript.sh
#!/bin/bash

read -p "Enter a path to a file: " file_to_copy
file_to_copy=$(eval echo $file_to_copy)
echo "Entered $file_to_copy"
cp "$file_to_copy" /tmp

Je vous suggérerais également d'utiliser des guillemets autour de la substitution de commande $( . . .) pour vous assurer que les fichiers contenant des espaces et des caractères spéciaux seront correctement capturés dans la variable file_to_copy

ADDITION

Comme indiqué dans les commentaires, eval intégré peut être dangereux.

Personnellement, j'utilise assez souvent la commande readlink dans mes scripts et évite d'utiliser ~. Et puisque dans ce script, vous demandez quand même une entrée utilisateur, pourquoi ne pas utiliser des arguments en ligne de commande? Ainsi:

xieerqi:
$ ./copyScript.sh testFile.txt                                
/home/xieerqi/testFile.txt

xieerqi:
$ cat copyScript.sh                                           
#!/bin/bash

FILE="$(readlink -f "$@" )"

echo $FILE
# uncomment for copying
# cp $FILE /tmp

nom de répertoire et nom de base

GNU coreutils fournit deux commandes, basename et dirname. basename affiche le dernier élément du chemin et dirname tout ce qui précède le dernier élément. On pourrait utiliser le développement de paramètres internes de bash pour faire la même chose, mais puisque nous avons ces outils - pourquoi ne pas les utiliser:

xieerqi:
$ ./copyScript.sh                                             
Enter path to file: ~/testFile.txt
File entered is  /home/xieerqi/testFile.txt

xieerqi:
$ ./copyScript.sh                                             
Enter path to file: ~/sumFile.txt
File entered is  /home/xieerqi/sumFile.txt
ERROR, file doesn't exist

xieerqi:
$ cat copyScript.sh                                           
#!/bin/bash

read -p "Enter path to file: " FILEPATH

DIRPATH="$(dirname "$FILEPATH")"
FILENAME="$(basename "$FILEPATH" )"

if [ "$DIRPATH" == "~"   ];then
  DIRPATH="$HOME"
fi

FILEPATH="$DIRPATH"/"$FILENAME"
echo "File entered is " "$FILEPATH"

[ -e "$FILEPATH"  ] || { echo "ERROR, file doesn't exist"; exit 1;}
2
Sergiy Kolodyazhnyy

Essayez ces commandes dans votre script:

#!/bin/bash
read -p "Enter a path to a file: " file_to_copy
file_to_copy=$(bash -c "echo $file_to_copy")
file_to_copy=${file_to_copy/~\//$HOME\/}
cp "${file_to_copy}" /tmp

Explication:

  • La troisième ligne développera env valeurs de variable s'il y en a.

  • La quatrième ligne du code ci-dessus essaiera de rechercher ~ dans votre variable file_to_copy et si elle est trouvée, elle sera remplacée par $HOME chemin.

  • Et \/ ici \ est un caractère de séquence d'échappement inversée pour /, car nous voulons remplacer ~/ par $HOME/.

4
snoop