Як "find -exec" передає імена файлів з пробілами?


14

Якщо у мене є каталог, який містить деякі файли, імена яких мають пробіли, наприклад

$ ls -1 dir1
file 1
file 2
file 3

Я можу успішно скопіювати їх у інший каталог на зразок цього:

$ find dir1 -mindepth 1 -exec cp -t dir2 {} +

Однак висновок find dir1 -mindepth 1містить пропущені пробіли:

$ find dir1 mindepth 1
dir1/file 1
dir1/file 3
dir1/file 3

Якщо я використовую print0замість print, висновок все ще містить пропущені пробіли:

$ find dir1 mindepth 1 -print0
dir1/file 1dir1/file 2dir1/file 3

Щоб скопіювати ці файли вручну за допомогою cp, мені потрібно вийти з пробілів; але здається, що це зайве, коли cpнадходять аргументи findнезалежно від того, використовую я +або \;в кінці команди.

У чому причина цього?

Відповіді:


8

findКоманда виконує команду безпосередньо. Команда, включаючи аргумент імені файлу, не буде оброблятися оболонкою або чим-небудь іншим, що може змінити ім'я файлу. Це дуже безпечно.

Ви впевнені, що не потрібно уникати імен файлів, представлених {}у findкомандному рядку.

findпередає необроблене ім'я файлу з диска безпосередньо у внутрішній список аргументів -execкоманди, у вашому випадку - cpкоманди.


1
Коротше кажучи, він find..execможе самостійно обробляти дивні назви файлів ..
heemayl

2
Перше правило linux club - ти не розбираєш ls
Сергій Колодяжний

5

Питання двоскладове:

  • як же find керувати за програмами обробки викликів з використанням -execне стикаючись з проблемами просторів , вкладених в іменах файлів, і
  • який хороший -print0варіант?

По-перше, findздійснює системний виклик, фактично один із групи пов'язаних дзвінків, що називаються "exec" . Він передає ім'я файлу як аргумент безпосередньо цьому виклику, який потім передається безпосередньо (після створення нового процесу), не втрачаючи інформації про ім'я файлу.

POSIX findособливість +пояснюється наступним чином , в обгрунтуванні :

Особливістю findутиліти SVR4 був -execпервинний + термінатор. Це дозволило згрупувати назви файлів, що містять спеціальні символи (особливо символи нового рядка ), без проблем, які виникають, якщо такі назви файлів переносяться xargs. Інші реалізації додали інші способи подолати цю проблему, зокрема -print0первинний, який записав назви файлів з нульовим байтовим термінатором. Це було розглянуто тут, але не прийнято. Використання нульового термінатора означало, що будь-яка утиліта, яка збиралася обробити -print0висновок пошуку, повинна додати нову опцію для розбору нульових термінаторів, які вона зараз читатиме.

Це « в зокрема-print0 , первинний» відноситься до GNU findі xargsякі вирішують цю проблему по-іншому. Він також підтримується FreeBSD findта xargs. Якщо ви додали до виклику -0опцію (див . Сторінку керівництва ) xargs, програма приймає рядки, що закінчуються символами "null byte". У свою чергу, xargsвикликає exec -функції, щоб зробити свою роботу. Основна відмінність між функцією -print0та -0ознакою від +функції полягає в тому, що перша передає назви файлів по трубі, а друга - ні. Розробники знаходять використання майже для будь-якої функції; труби не є винятком.

Повернення до прикладу OP, який використовує -tпараметр cp: що не знайдено в POSIX cp . Скоріше, це розширення (відоме також як "нестандартна функція"), надане GNU cp . -0Розширення xargsне поліпшить цей приклад, але є й інші випадки , коли можуть бути ефективно використані по підтримці на увазі , що є портативна альтернатива +, яка GNU findприймає.


-1

( Це має бути коментар, але він занадто великий. )

Для тих, хто любить спробувати речі:

Створіть сценарій з переліком позиційних параметрів, переданих у ньому, назвіть його list_positional_parameters.sh.

#!/bin/bash

# http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_09_07.html
# Try globbing patterns, e.g. "X[[:digit:]][[:digit:]]" to see what happens

if [ $# -lt 1 ]; then
   echo "Usage: $0 and then at least one parameter"
   exit 1
fi

counter=1

while (($#)); do
   echo "$counter = '$1'"
   # pop positional argument 1 off the stack of positional arguments
   shift
   (( counter++ ))
done

Запустити findз ним у деякому каталозі $ dir:

find "$dir" -exec ./list_positional_parameters.sh '{}' ';' | less

Як і очікувалося, у всіх викликах є лише один параметр, ім'я файлу, чи є пробіли в його імені чи ні.


1
Ви також можете використовувати printfяк printf '"%s"\n' "$@"для роздрукування всіх цитованих позиційних аргументів для візуального огляду.
Kusalananda
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.