Как я выполняю действие со всеми файлами с определенным расширением в подпапках изящным способом?

Старые выпуски Fedora сохранены в http://archive.fedoraproject.org/pub/archive/fedora/, например, Ядро Fedora 4.

19
10.10.2012, 00:47
5 ответов

Канонический путь состоит в том, чтобы сделать

find . -name '*.jpg' -exec echo {} \;

(замена \; с + передать больше чем один файл echo за один раз)

или (конкретный GNU, хотя некоторые BSDs теперь имеют его также):

find . -name '*.jpg' -print0 | xargs -r0 echo

zsh:

for i (**/*.jpg(D)) echo $i
27
27.01.2020, 19:45
  • 1
    При использовании xargs-0 необходимо соответствовать ему-0 –  itsbruce 09.10.2012, 11:35
  • 2
    @MichaelKjörling, никакое заключение в кавычки {} не имеет никакого значения. {} расширен находкой, не оболочкой. Улучшение не должно было бы использовать echo который разворачивает escape-последовательности как \b (по крайней мере, совместимый Unix echos). –  Stéphane Chazelas 09.10.2012, 11:46
  • 3
    @sch - Вы уверенный? find шоу страницы справочника find . -type f -exec file '{}' \; в EXAMPLES раздел. Возможно, некоторые оболочки будут рассматривать фигурные скобки особенно. –  QuasarDonkey 09.10.2012, 16:38
  • 4
    Кавычки не вредят, но не имеют никакого значения. Весь из '{}', \{\}, {}, "{}", '{'} расширены оболочкой (безотносительно подобной Границе оболочки) к одному аргументу, чтобы найти, что это - эти два символа "{" и "}". Замена "находит" с "эхом, находят", или printf '<%s>\n' find если Вы хотите перепроверить. –  Stéphane Chazelas 09.10.2012, 23:40
  • 5

Лучшие ответы были уже даны.

Но обратите внимание, что пробелы не являются единственной проблемой в коде, который Вы дали. вкладка, символы новой строки и подстановочные символы являются также проблемой.

С

IFS='
'
set -f
for i in $(find . -name '*.jpg'); do echo "$i"; done

Затем только символы новой строки являются проблемой.

2
27.01.2020, 19:45

То, что Вы упомянули, является одной из основных проблем, с которыми сталкиваются люди, когда они пытаются считать имена файлов. Иногда, люди с ограниченными знаниями и наличием неправильного представления файловой структуры и структуры папок склонны забывать, что "В UNIX Все - файл". Таким образом, они не понимают, что должны обработать пробелы также, поскольку имя файла может состоять из 2 или больше слов с пробелами.

Решение: Таким образом, один из более известных способов сделать это состоит в том, чтобы сделать чистое чтение.

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

СЦЕНАРИЙ:

 find /path/to/files/ -iname "*jpg" | \
  while read I; do
   cp -v --parent "$I" /backup/dir/
  done

Здесь я читаю файлы путем предоставления пути им и независимо от того, что я читаю, я сохраняю их в переменной I, который я заключу в кавычки позже при обработке его для сохранения пробелов, чтобы обработать его правильно.

Надежда это помогает Вам в некотором роде.

1
27.01.2020, 19:45
  • 1
    "все - файл", относится к чему-то еще. Ваше решение является конкретным ОРУЖИЕМ и не справляется с обратной косой чертой или символами новой строки в именах файлов. "в то время как считано" циклы в оболочках (IMO) часто признак плохой практики сценариев оболочки. –  Stéphane Chazelas 09.10.2012, 12:57
  • 2
    @sch: ха, и я раньше думал, это в порядке. Спасибо за указание на это. Я, вероятно, должен посмотреть на него больше. –  The Dark Knight 09.10.2012, 14:24
  • 3
    извините, я имел в виду "GNU", не "ОРУЖИЕ" выше (это - первый раз, когда я понимаю, что это - анаграммы BTW...), –  Stéphane Chazelas 09.10.2012, 14:26

Просто с find и bash :

find . -name '*.jpg' -exec bash -c '
    echo "treating file $1 in bash, from path : ${1%/*}" 
' -- {} \;

Таким образом, мы используем $1 в ударе, как в основном сценарии, это открывается, хорошие перспективы к работает, любой усовершенствовал (или не) задачи.

Более эффективный путь (чтобы избежать необходимости запускать новый удар для каждого файла):

find . -name '*.jpg' -exec bash -c 'for i do
    echo "treating file $i in bash, from path : ${i%/*}" 
  done' -- {} +
1
27.01.2020, 19:45

В последней версии удара можно использовать globstar опция:

shopt -s globstar
for file in **/*.jpg ; do
    echo "$file"
done

Для простых действий можно даже пропустить цикл полностью:

echo **/*.jpg
0
27.01.2020, 19:45
  • 1
    , В то время как это работает в zsh (где функция, порожденная из) и с ksh93 (с set -G), это не должно использоваться в ударе, поскольку версия удара существенно повреждается (точно так же, как GNU grep -r) поскольку это убывает в символьные ссылки на каталоги (эквивалентный find -L или zsh's ***/*.jpg). Также обратите внимание, что вопреки находке, это будет ommit dotfiles и не убывать в dotdirs (по умолчанию). –  Stéphane Chazelas 09.10.2012, 11:53

Теги

Похожие вопросы