Сначала я сделаю тестовую базу - 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функции glob:
sh -cxvf 'echo file[1-5]'
ВЫХОД
echo file[1-5]
+ echo 'file[1-5]'
file[1-5]
Поэтому, когда вы запускаете команду в оболочке, настроенной с параметрами по умолчанию, такими mv *как оболочка, расширяет в *слове список аргументов всех файлов в текущем каталоге, отсортированных по локали. Он выполняет системный вызов 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с содержимым каталога (если он не пустой и не включает файлы / папки с именами, начинающимися с .) в качестве списка аргументов. mvPOSIX указывается, чтобы интерпретировать свой последний аргумент как каталог, если он вызывается с более чем двумя аргументами - таким же образом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символ, если цель не заканчивается на a /slash, и последний компонент имени пути исходного_файла . Эта вторая форма предполагается, когда последний операнд называет существующий каталог.
Так что, если *расширяется до: