Спочатку я зроблю тестову базу - 5 файлів і одна папка:
touch file1 file2 file3 file4 file5
mkdir folder
Далі я запускаю тестову команду. У -v
параметр вказує , що я хочу кожну команду оболонка виконує бути роздрукована в stderr
. У -x
параметрі указует , що я хочу той же друкується stderr
- але я хочу зробити це після того, як команда обчислюється , але перш , ніж оболонка запускає його.
sh -cxv 'echo mv *'
ВИХІД
echo mv *
+ echo mv file1 file2 file3 file4 file5 folder
mv file1 file2 file3 file4 file5 folder
Отже, ви бачите, що команда, яку я подаю оболонці, echo mv *
і команда, яку виконує оболонка після *
розширення, echo mv
супроводжуються всіма цими файлами та папкою.
За замовчуванням оболонка розширить глобуси :
sh -cxv 'echo file[1-5]'
ВИХІД
echo file[1-5]
+ echo file1 file2 file3 file4 file5
file1 file2 file3 file4 file5
Це результат set [+-]f
функції глобуса:
sh -cxvf 'echo file[1-5]'
ВИХІД
echo file[1-5]
+ echo 'file[1-5]'
file[1-5]
Таким чином, коли ви запускаєте команду в оболонці, налаштованій за замовчуванням, наприклад mv *
оболонка розширює в *
слово список аргументів всіх файлів у поточному каталозі, відсортованих за місцевістю. Він робить syscall exec(ve)
для mv
(по суті) із доданим цим аргументом списком. Таким чином mv
отримує всі аргументи, коли оболонка обробляє їх і сортує. Окрім того, strace
щоб побачити ці ефекти, ви можете знову використовувати налагодження, як:
sh -s -- mv * <<\SCRIPT
sed -n l /proc/$$/cmdline
echo "$@"
SCRIPT
ВИХІД
sh\000-s\000--\000mv\000file1\000file2\000file3\000file4\000file5\000folder\
\000$
mv file1 file2 file3 file4 file5 folder
І портативно:
( PS4= IFS=/; set -x mv *; : "/$*/" ) 2>&1
ВИХІД
: /mv/file1/file2/file3/file4/file5/folder/
В основному, оболонка виконується mv
зі вмістом каталогу (якщо він не порожній і не включає файли / папки з іменами, що починаються з .
) в якості списку аргументів. mv
є POSIX вказано інтерпретувати його останній аргумент як каталог , якщо він викликається з більш ніж двома аргументами - так само , як ln
це (тому що, насправді, вони неймовірно аналогічні інструменти в основної функції) .
Досить, echo
хоча:
sh -cxv 'mv *' ; ls
ВИХІД
mv *
+ mv file1 file2 file3 file4 file5 folder
folder/
Усі файли були переміщені в остаточний аргумент - тому що це папка. А що робити, якщо це не папка?
sh -cxv 'cd *; mv *'; ls . *
ВИХІД
cd *; mv *
+ cd folder
+ mv file1 file2 file3 file4 file5
mv: target ‘file5’ is not a directory
.:
folder/
folder:
file1 file2 file3 file4 file5
Ось як вказує POSIX mv
в такому випадку:
mv [-if] source_file target_file
mv [-if] source_file... target_dir
У першій формі конспекту mv
утиліта повинна перемістити файл, названий операндом source_file, до місця призначення, визначеного target_file . Ця перша форма конспекту передбачається, коли остаточний операнд не називає існуючий каталог і не є символічним посиланням, що посилається на існуючий каталог. У цьому випадку, якщо source_file називає файл, який не є каталогом, а target_file закінчується заднім /slash
символом, він mv
трактує це як помилку, і жодні операнди source_file не обробляться.
У другій формі конспекту слід mv
перемістити кожен файл, названий операндом source_file, до файла призначення в існуючому каталозі, названому операндом target_dir , або посилатися на нього, якщо target_dir є символічним посиланням, що посилається на існуючий каталог. Шлях призначення для кожного ісходний_файл буде конкатенацией цільового каталогу, один /slash
символ , якщо мета не закінчується на /slash
, а останній шляху компонента ісходний_файл . Ця друга форма передбачається, коли кінцевий операнд називає існуючий каталог.
Тож якщо *
розширюється на: