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 saisit le chemin d’access complet à un fichier de test, par exemple / home / $ USER / test à l’invite, le script s’exécutera comme prévu et créera 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 est-elle incapable de trouver une représentation équivalente du chemin du fichier lorsqu’elle est entrée?

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’assignation de variable que je me suis trompée, mais que je n’arrive pas à comprendre.

Merci.

Ce qui se passe, c’est que vous demandez littéralement au shell de trouver ~/test partir du répertoire dans lequel se trouve le script. En d’autres termes, si vous exécutez à partir de /home/$USER , il recherchera le fichier test dans le sous-répertoire nommé ~ , et non le extension /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 va se développer ~ .

 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 

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

UNE ADDITION

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

Personnellement, j’utilise la commande readlink assez souvent 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 affiche tout ce qui précède le dernier élément. On pourrait utiliser l’expansion des parameters 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;} 

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 les valeurs des variables env , le cas échéant.

  • La quasortingè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 path.

  • Et \/ here \ est un caractère de séquence d’échappement avec une barre oblique inversée pour / , car nous voulons remplacer ~/ par $HOME/ .