Intereting Posts
Как удалить сообщение при открытии терминала / решить? Плата Jetson-K1 медленнее, чем ожидалось, – «отсутствие частотной характеристики» Каков самый последний файл журнала в утилите logrotate Узнайте, какие исходные файлы ядра были использованы при компиляции ядра FreeDOS в Linux Как запустить gunicorn в качестве демона systemd Как использовать регулярное выражение внутри exec с помощью find? FreeNX закрывает отображение сразу после успешного подключения в OpenSUSE 12.2 Преобразование разрешений в вывод `ls -l` в восьмеричный Каковы относительные достоинства различных стандартных архивных утилит Unix? Сдвиньте каждый режим на постоянный коэффициент звукового сигнала В чем разница между терминалом root и sudo? Возможно ли сделать scp сбоем, когда вы делаете локальную копию? Заменить значения в столбце, содержащем числа Как включить Shift Lock? (Sticky shift key)

Как интегрировать команду mv после команды find?

Я ищу файлы, имена которых содержат AAA в своем пути, используя следующую команду:

 find path_A -name "*AAA*" 

Учитывая результат, показанный приведенной выше командой, я хочу переместить эти файлы в другой путь, скажем path_B . Вместо того, чтобы перемещать файл один за другим, могу ли я оптимизировать команду, перемещая эти файлы сразу после команды find?

С GNU mv :

 find path_A -name '*AAA*' -exec mv -t path_B {} + 

Это будет использовать опцию find -exec которая заменяет {} с каждым результатом поиска по очереди и запускает команду, которую вы ему даете. Как объясняется в man find :

  -exec command ; Execute command; true if 0 status is returned. All following arguments to find are taken to be arguments to the command until an argument consisting of `;' is encountered. 

В этом случае мы используем + версию -exec чтобы мы выполняли как можно меньше mv операций:

  -exec command {} + This variant of the -exec action runs the specified command on the selected files, but the command line is built by appending each selected file name at the end; the total number of invoca‐ tions of the command will be much less than the number of matched files. The command line is built in much the same way that xargs builds its command lines. Only one instance of `{}' is allowed within the command. The command is executed in the starting directory. 

Вы могли бы сделать что-то вроде ниже.

 find path_A -name "*AAA*" -print0 | xargs -0 -I {} mv {} path_B 

Где,

  1. -0 Если есть пробелы или символы (включая новые строки), многие команды не будут работать. Эта опция берет на себя имена файлов с пробелом.
  2. -I Заменить имена replace-str в начальных аргументах именами, считанными со стандартного ввода. Кроме того, некотируемые пробелы не прерывают входные элементы; вместо этого разделитель является символом новой строки.

тестирование

Я создал два каталога как sourcedir и destdir . Теперь я создал кучу файлов внутри sourcedir как file1.bak , file2.bak и file3 with spaces.bak

Теперь я выполнил команду как,

 find . -name "*.bak" -print0 | xargs -0 -I {} mv {} /destdir/ 

Теперь, внутри destdir , когда я это делаю, я мог видеть, что файлы переместились из sourcedir в destdir .

Рекомендации

http://www.cyberciti.biz/faq/linux-unix-bsd-xargs-construct-argument-lists-utility/

-exec – лучший способ сделать это. Если по какой-либо причине это не вариант, вы также можете прочитать результаты в цикле:

 find path_A -name "*AAA*" -print0 | while IFS= read -r -d $'\0' file; do mv "$file" path_B; done 

Это безопасный способ, он может иметь дело с именами файлов, которые содержат пробелы, символы новой строки или другие странные символы. Более простой способ, но тот, который терпит неудачу, если ваши имена файлов не состоят только из простых буквенно-цифровых символов ,

 mv $(find path_A -name "*AAA*") path_B 

Но используйте цикл while.

Для пользователей OS X, которые сталкиваются с этим вопросом, синтаксис в OS X немного отличается. Предполагая, что вы не хотите искать рекурсивно в подкаталогах path_A :

 find path_A -maxdepth 1 -name "*AAA*" -exec mv {} path_B \; 

Если вы хотите рекурсивно искать все файлы в path_A :

 find path_A -name "*AAA*" -exec mv {} path_B \; 

Другой путь

 for f in `find path_A -name "*AAA*"`; do mv $f /destination/dir/; done 

Используя только функции POSIX find (а также mv ):

 find path_A -name '*AAA*' -exec sh -c 'mv "$@" path_B' find-sh {} + 

Дальнейшее чтение:

  • Почему происходит перебор находок на выходе плохой практики?