Per prima cosa creerò una base di test: 5 file e una cartella:
touch file1 file2 file3 file4 file5
mkdir folder
Quindi eseguirò un comando di prova. L' -v
opzione specifica che desidero che tutti i comandi eseguiti dalla shell vengano stampati stderr
. L' -x
opzione specifica che voglio che lo stesso sia stampato stderr
, ma lo voglio fatto dopo che il comando è stato valutato ma prima che la shell lo esegua.
sh -cxv 'echo mv *'
PRODUZIONE
echo mv *
+ echo mv file1 file2 file3 file4 file5 folder
mv file1 file2 file3 file4 file5 folder
Quindi vedi che il comando I feed the shell è echo mv *
e il comando che la shell esegue dopo l' *
espansione è echo mv
seguito da tutti quei file e la cartella.
Per impostazione predefinita, la shell espanderà globs come:
sh -cxv 'echo file[1-5]'
PRODUZIONE
echo file[1-5]
+ echo file1 file2 file3 file4 file5
file1 file2 file3 file4 file5
Questo è il risultato della set [+-]f
funzione glob:
sh -cxvf 'echo file[1-5]'
PRODUZIONE
echo file[1-5]
+ echo 'file[1-5]'
file[1-5]
Quindi quando si esegue un comando in una shell configurata con opzioni predefinite come mv *
la shell si espande nella *
parola un elenco di argomenti di tutti i file nella directory corrente ordinati in base alle impostazioni locali. Fa la syscall exec(ve)
per mv
(essenzialmente) con questa lista di argomenti aggiunta. Quindi mv
ottiene tutti gli argomenti mentre la shell li stravolge e li ordina. Oltre strace
a vedere questi effetti, puoi usare di nuovo il debug come:
sh -s -- mv * <<\SCRIPT
sed -n l /proc/$$/cmdline
echo "$@"
SCRIPT
PRODUZIONE
sh\000-s\000--\000mv\000file1\000file2\000file3\000file4\000file5\000folder\
\000$
mv file1 file2 file3 file4 file5 folder
E portabilmente:
( PS4= IFS=/; set -x mv *; : "/$*/" ) 2>&1
PRODUZIONE
: /mv/file1/file2/file3/file4/file5/folder/
Fondamentalmente, la shell viene eseguita mv
con il contenuto della directory (se non è vuota e non include file / cartelle con nomi che iniziano con .
) come elenco di argomenti. mv
è POSIX specificato di interpretare il suo argomento finale come una directory se viene invocato con più di due argomenti - allo stesso modo ln
è (perché, in effetti, sono strumenti incredibilmente simile in funzione sottostante) .
Basta echo
però:
sh -cxv 'mv *' ; ls
PRODUZIONE
mv *
+ mv file1 file2 file3 file4 file5 folder
folder/
Tutti i file sono stati spostati nell'argomento finale, perché è una cartella. E se non fosse una cartella?
sh -cxv 'cd *; mv *'; ls . *
PRODUZIONE
cd *; mv *
+ cd folder
+ mv file1 file2 file3 file4 file5
mv: target ‘file5’ is not a directory
.:
folder/
folder:
file1 file2 file3 file4 file5
Ecco come POSIX specifica mv
dovrebbe comportarsi in quel caso:
mv [-if] source_file target_file
mv [-if] source_file... target_dir
Nel primo modulo di sinossi, l' mv
utilità deve spostare il file indicato dall'operando source_file nella destinazione specificata dal target_file . Questo primo modulo di sinossi viene assunto quando l'operando finale non nomina una directory esistente e non è un collegamento simbolico che fa riferimento a una directory esistente. In questo caso, se source_file nomina un file non di directory e target_file termina con un /slash
carattere finale , mv
lo considererà un errore e nessun operando source_file verrà elaborato.
Nel secondo modulo di sinossi, mv
ogni file denominato da un operando source_file viene spostato in un file di destinazione nella directory esistente denominata dall'operando target_dir , oppure indicato se target_dir è un collegamento simbolico che fa riferimento a una directory esistente. Il percorso di destinazione per ciascun file_origine deve essere la concatenazione della directory di destinazione, un singolo /slash
carattere se la destinazione non termina in a /slash
e l'ultimo componente percorso del file di origine . Questo secondo modulo viene assunto quando l'operando finale nomina una directory esistente.
Quindi se si *
espande in: