Dans un script, si je mets #!/bin/bash
en haut, cela fonctionnera bien :
cp directory/{foo,bar} destination
Cependant, avec sh, cela donnera l'erreur "aucun fichier ou répertoire de ce type". Dans sh, existe-t-il un autre moyen d'atteindre le même objectif final avec une seule commande ?
Réponse acceptée :
Comme vous l'avez observé, tous les shells ne prennent pas en charge l'expansion des accolades.
Méthode 1 :deux chemins distincts (c'est-à-dire écrire deux fois le préfixe)
Si votre objectif est vraiment de le faire en une seule commande, un moyen simple est :
cp directory/file1 directory/file2 destination
Le cp
La commande prend en charge plusieurs arguments source suivis d'un argument de destination. En fait, c'est ce qui se passe avec la commande qui fonctionne pour vous dans Bash. Bash effectue une expansion des accolades, qui convertit la commande que vous avez utilisée en celle indiquée ci-dessus. Autrement dit, lorsque vous exécutez cp directory/{file1,file2} destination
dans Bash, le cp
la commande ne voit jamais d'accolades.
Une telle commande est simple et facile à comprendre. Je suggère d'y réfléchir.
Méthode 2 :une variable pour le préfixe
Mais si votre objectif est d'éviter de répéter vous-même, alors vous préférerez peut-être ne pas le faire de cette façon, surtout si directory
est en fait un long chemin. Après tout, si vous devez modifier le chemin plus tard dans le script, vous devrez apporter des modifications aux deux occurrences.
Vous pouvez stocker le directory
(ou quoi que ce soit, chemin vraisemblablement plus long) dans une variable shell :
dir='directory'
cp "$dir/file1" "$dir/file2" destination
$dir
est l'expansion des paramètres. Le shell le remplace par la valeur contenue dans la variable dir
. Lorsque vous utilisez l'expansion des paramètres, vous ne devez pas omettre les guillemets doubles, sauf dans les rares cas où vous souhaitez que le fractionnement et la globalisation des champs soient effectués. (Cela s'applique également à Bash.)
Ce sont deux commandes, mais si votre objectif réel est d'éviter de vous répéter, c'est peut-être ce que vous voulez. Vous pourriez écrire
dir='directory'; cp "$dir/file1" "$dir/file2" destination
pour en faire "une seule commande", mais ce n'est pas plus court et c'est un peu moins lisible.
(Notez que vous ne pouvez pas simplement supprimer le ;
là. Le résultat de faire serait une commande bien formée, mais cela ne ferait pas ce que vous voulez. Il exécuterait le cp
commande, en passant une variable d'environnement appelée dir
avec la valeur directory
dans le cp
l'environnement de la commande. Puisque c'est la coquille et non le cp
commande, qui développe dir
, cela ne fonctionnerait pas.)
Méthode 3 :cd
ig au préfixe
Si votre script ne fait rien d'autre après avoir effectué cette opération, ou peu importe le répertoire actuel pour les commandes suivantes, alors if destination
est un chemin absolu , vous pouvez utiliser :
cd directory
cp file1 file2 destination
Mais je ne le recommande pas pour les scripts à moins que votre script n'exécute des actions ultérieures qui bénéficient d'être exécutés à partir de ce répertoire, ou peuvent être écrits plus brièvement ou simplement lorsqu'ils sont exécutés à partir de ce répertoire. Sauf lorsque le répertoire à partir duquel un script est exécuté est significatif au but du script, s'y fier peut rendre le script plus difficile à raisonner ; de plus, si le cd
la commande réussit mais le cp
La commande échoue, les messages d'erreur résultants peuvent être moins qu'entièrement éclairants. Au lieu de cela, je mentionne la technique de cd
vers le répertoire source car c'est un modèle utile pour interactive utilisation du shell.
(Comme l'a souligné Hannu, vous pouvez regrouper n'importe quel nombre de commandes dans (
)
pour les exécuter dans un sous-shell et les modifications apportées à l'environnement du shell, y compris l'effet de cd
, ne persistera pas après l'exécution de la commande. C'est une technique largement utile, et c'était une omission substantielle que je ne l'avais pas mentionnée. Notez, cependant, que cela n'atténue pas les problèmes liés au fait d'avoir un chemin relatif pour destination
.)
Notez que si le cd
échoue, les autres commandes continueront généralement à s'exécuter. Cela pourrait copier différents fichiers que vous ne voulez pas copier (s'il existe d'autres fichiers portant les mêmes noms dans le répertoire à partir duquel le script était exécuté) ou produire des messages d'erreur déroutants. Vous pouvez donc préférer :
cd directory && cp file1 file2 destination
Le &&
entraîne l'exécution de la deuxième commande uniquement si la première commande a réussi. Notez que cela n'annule toujours pas l'effet de l'exécution de la première commande. Une fois le tout exécuté, vous serez toujours dans le directory
, sauf si vous l'avez exécuté dans un sous-shell avec (
)
.