С mv
cannot move 'foo' to a subdirectory of itself
безвреден в этом случае, вы можете игнорировать это. Я имею в виду mv
переместить остальных, несмотря на предупреждение. Однако статус выхода не будет 0
, это может быть серьезным препятствием в сценариях, где вы хотите прервать или предпринять корректирующее действие, если mv
это не удалось.
Об этом уже говорилось в комментарии : вы можете замолчать mv
, перенаправив stderr с помощью 2>/dev/null
; другие предупреждения или ошибки также будут перенаправлены.
Я думаю, что вы не можете легко «уточнить шаблон, чтобы ограничить исходный файл файлами, а не каталогами». Тем не менее, вы можете использовать подход, который не соответствует буквальному foo
. Следующий подход не имеет ничего общего с файлами или каталогами; только с именами, потому что глобусы имеют дело с именами; так что в некоторых случаях этого может быть недостаточно.
*foo*
Глоб соответствует четыре дизъюнктивных видов объектов:
foo
сам- foo только с префиксом, как
bar-foo
- вы можете сопоставить их с помощью*?foo
- Foo с префиксом и постфикса, как
bar-foo-baz
-*?foo?*
- Фу только с постфиксом, как
foo-baz
-foo?*
Для исключения foo
вам нужны только последние три (2-4), поэтому первый подход может быть:
mv *?foo *?foo?* foo?* foo/
Если у вас не установлена nullglob
опция оболочки, любой шаблон должен соответствовать чему-либо, иначе он будет передан mv
буквально. Ты не хочешь этого. Решение состоит в том, чтобы заранее выполнить следующую команду:
shopt -s nullglob
Эта опция оболочки заставит любой непревзойденный шар расширяться до нуля. Советую также изучить dotglob
вариант.
Обратите внимание, что *?foo*
соответствует (2-3). Аналогично *foo?*
совпадает (3-4). Кроме того, считает --
сказать, mv
что все последующие аргументы не являются опциями. Таким образом, файл вроде --foo
не будет интерпретироваться как (неизвестная) опция. Это приводит к двум лучшим командам:
mv -- *?foo* foo?* foo/
или же
mv -- *?foo *foo?* foo/
Неважно, какой вы выберете. Просто не используйте mv *?foo* *foo?* foo/
; он будет проходить (например) bar-foo-baz
в mv
два раза (то есть, как два отдельных аргумента), таким образом, генерируется ошибка, когда инструмент пытается переместить этот объект во второй раз.
Когда совпадения не найдены, мои mv
команды выродятся mv foo/
и выдадут ошибку. Ваша оригинальная mv
команда (с nullglob
unset) получит литерал *foo*
и выдаст еще одну ошибку.
Пример сеанса консоли:
$ shopt -s nullglob $ mkdir foo $ touch bar-foo bar-foo-baz foo-baz xyfooz.tex ./--foo $ mv -v -- *?foo* foo?* foo/ 'bar-foo' -> 'foo/bar-foo' 'bar-foo-baz' -> 'foo/bar-foo-baz' '--foo' -> 'foo/--foo' 'xyfooz.tex' -> 'foo/xyfooz.tex' 'foo-baz' -> 'foo/foo-baz' $
Простой взлом
Допустим, dummy
не существует.
mv foo dummy mv *foo* dummy/ mv dummy foo
Переименование каталога должно быть очень быстрым в файловых системах на основе inode. Программы, в которых файлы изнутри foo/
уже открыты, не должны ни мешать, ни ломаться, потому что важен именно индекс. Однако, если какая-либо программа должна открыть файл (по пути в том числе foo/
) между первым и третьим mv
, это не удастся. Могут возникнуть и другие побочные эффекты (представьте, что программа стороннего производителя воссоздается foo/
), поэтому я называю этот подход хаком. Подумайте дважды, прежде чем использовать его.
С в find
любом случае
Разобрать файлы из каталогов - это работа для find
. То, что вы сделали, find
это в основном правильный путь. То, что вы хотите сделать (и то, что я сделал выше) с помощью mv
оболочки, кажется… ну, в большинстве случаев «менее правильным». Это ваша команда:
find . -maxdepth 1 -type f -name '*foo*' -exec mv {} foo \;
Это find
будет запускаться отдельно mv
для каждого сопоставленного файла, вся команда будет работать плохо. По этой причине можно захотеть перейти на сингл mv
. Если это ваша точка зрения (и ваша, mv
и find
вы достаточно богаты), то вы должны рассмотреть этот «очень правильный» способ:
find . -maxdepth 1 -type f -name '*foo*' -exec mv -t foo/ -- {} +
Преимущества перед вашей find
командой и / или над простой mv
с glob (s):
- один
mv
может получить несколько файлов для работы; - Тем не менее, если слишком много файлов для одной командной строки, чтобы обработать,
find
будет запущен дополнительныйmv
процесс (ы); - в случае, когда ни один файл не соответствует шаблону,
mv
не будет запускаться вообще; - благодаря
--
файлу подобное--foo
не будет интерпретироваться как (неизвестная) опцияmv
;