Je vais d'abord faire une base de test - 5 fichiers et un dossier:
touch file1 file2 file3 file4 file5
mkdir folder
Ensuite, je vais exécuter une commande de test. L' -v
option spécifie que je veux que chaque commande exécutée par le shell soit imprimée stderr
. L' -x
option spécifie que je veux que le même soit imprimé stderr
- mais je veux que ce soit fait après que la commande soit évaluée mais avant que le shell ne l'exécute.
sh -cxv 'echo mv *'
SORTIE
echo mv *
+ echo mv file1 file2 file3 file4 file5 folder
mv file1 file2 file3 file4 file5 folder
Vous voyez donc que la commande que j'alimente le shell est echo mv *
et que la commande que le shell exécute après avoir *
été développée est echo mv
suivie par tous ces fichiers et le dossier.
Par défaut, le shell étendra les globes comme:
sh -cxv 'echo file[1-5]'
SORTIE
echo file[1-5]
+ echo file1 file2 file3 file4 file5
file1 file2 file3 file4 file5
Ceci est le résultat de la set [+-]f
fonction glob:
sh -cxvf 'echo file[1-5]'
SORTIE
echo file[1-5]
+ echo 'file[1-5]'
file[1-5]
Ainsi, lorsque vous exécutez une commande dans un shell configuré avec des options par défaut comme mv *
le shell se développe dans le *
mot une liste d'arguments de tous les fichiers du répertoire en cours triés en fonction des paramètres régionaux. Il effectue l'appel système exec(ve)
pour mv
(essentiellement) avec cette liste d'arguments ajoutée. Obtient donc mv
tous les arguments lorsque le shell les globule et les trie. En plus de faire strace
pour voir ces effets, vous pouvez utiliser à nouveau le débogage comme:
sh -s -- mv * <<\SCRIPT
sed -n l /proc/$$/cmdline
echo "$@"
SCRIPT
SORTIE
sh\000-s\000--\000mv\000file1\000file2\000file3\000file4\000file5\000folder\
\000$
mv file1 file2 file3 file4 file5 folder
Et de façon portative:
( PS4= IFS=/; set -x mv *; : "/$*/" ) 2>&1
SORTIE
: /mv/file1/file2/file3/file4/file5/folder/
Fondamentalement, le shell s'exécute mv
avec le contenu du répertoire (s'il n'est pas vide et n'inclut pas les fichiers / dossiers commençant par .
) comme liste d'arguments. mv
est spécifié pour interpréter Posix son dernier argument en tant que répertoire si elle est invoquée avec plus de deux arguments - de la même manière ln
est (parce que, en fait, ils sont des outils incroyablement similaires dans la fonction sous - jacente) .
Assez echo
cependant:
sh -cxv 'mv *' ; ls
SORTIE
mv *
+ mv file1 file2 file3 file4 file5 folder
folder/
Tous les fichiers ont été déplacés dans l'argument final, car il s'agit d'un dossier. Et si ce n'est pas un dossier?
sh -cxv 'cd *; mv *'; ls . *
SORTIE
cd *; mv *
+ cd folder
+ mv file1 file2 file3 file4 file5
mv: target ‘file5’ is not a directory
.:
folder/
folder:
file1 file2 file3 file4 file5
Voici comment POSIX mv
doit se comporter dans ce cas:
mv [-if] source_file target_file
mv [-if] source_file... target_dir
Dans le premier formulaire de synopsis, l' mv
utilitaire doit déplacer le fichier nommé par l'opérande source_file vers la destination spécifiée par target_file . Cette première forme de synopsis est supposée lorsque l'opérande final ne nomme pas de répertoire existant et n'est pas un lien symbolique faisant référence à un répertoire existant. Dans ce cas, si source_file nomme un fichier non-répertoire et target_file se termine par un /slash
caractère de fin , mv
doit traiter cela comme une erreur et aucun opérande source_file ne sera traité.
Dans le deuxième formulaire de synopsis, mv
doit déplacer chaque fichier nommé par un opérande source_file vers un fichier de destination dans le répertoire existant nommé par l' opérande target_dir , ou référencé si target_dir est un lien symbolique faisant référence à un répertoire existant. Le chemin de destination pour chaque fichier source doit être la concaténation du répertoire cible, un seul /slash
caractère si la cible ne s'est pas terminée par un /slash
et le dernier composant de chemin d'accès du fichier source . Cette seconde forme est supposée lorsque l'opérande final nomme un répertoire existant.
Donc, si *
étend à: