6

find -exec с несколькими командами

4

Описание проблемы:

Я пытаюсь использовать команду find с опцией -exec для выполнения нескольких команд, но пока не могу добиться успешного выполнения. Могу ли я использовать такие команды, как приведенная ниже?

find *.txt -exec echo "$(tail -1 '{}'),$(ls '{}')" \;

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

5 ответ(ов)

9

Команда find принимает несколько частей -exec для выполнения указанной команды. Например:

find . -name "*.txt" -exec echo {} \; -exec grep banana {} \;

Обратите внимание, что во втором случае вторая команда будет выполнена только в том случае, если первая завершится успешно, как упомянул @Caleb. Если вы хотите, чтобы обе команды выполнялись независимо от их успешности или ошибки, вы можете использовать следующую конструкцию:

find . -name "*.txt" \( -exec echo {} \; -o -exec true \; \) -exec grep banana {} \;

Таким образом, команда grep будет выполнена для каждого найденного файла, независимо от результата выполнения echo.

1

Команда, которую вы привели, выполняет поиск всех каталогов в текущем и подкаталогах, затем для каждого найденного каталога выводит его имя дважды, разделенное строкой " x ". Давайте разберем ее по частям:

  • find . — ищет в текущем каталоге (.) и всех вложенных.
  • -type d — указывает, что нужно искать только каталоги.
  • -exec sh -c "..." \; — для каждого найденного каталога выполняет команду, указанную в кавычках.

Команда внутри sh -c делает следующее:

  • echo -n {} — выводит имя каталога без добавления новой строки.
  • echo -n ' x ' — выводит строку " x " без перехода на новую строку.
  • echo {} — затем снова выводит имя каталога, но уже с переходом на новую строку.

Таким образом, результатом выполнения будет строка вида:

имя_каталога x имя_каталога

Если у вас возникли дополнительные вопросы касаемо данной команды или поведения find, не стесняйтесь задавать!

0

Каждый из предложенных вариантов команд выполняет схожую задачу — извлечение последней строки из файлов с расширением .txt и вывод её в формате строка,имя_файла. Давайте рассмотрим каждую команду подробнее:

  1. Первая команда:

    find *.txt -exec awk 'END {print $0 "," FILENAME}' {} \;
    

    Эта команда использует awk для выбора последней строки каждого найденного текстового файла. Она выводит последнюю строку и имя файла, разделенные запятой. Однако данная команда не сработает, поскольку find не обрабатывает шаблон *.txt корректно. Лучше использовать:

    find . -name "*.txt" -exec awk 'END {print $0 "," FILENAME}' {} \;
    
  2. Вторая команда:

    find *.txt -exec sh -c 'echo "$(tail -n 1 "$1"),$1"' _ {} \;
    

    Этот вариант использует tail для получения последней строки из каждого файла. Он также правильно выводит строку с именем файла, разделенных запятой. Обратите внимание, что та же проблема с find (использование *.txt) сохраняется. Следует заменить её на:

    find . -name "*.txt" -exec sh -c 'echo "$(tail -n 1 "$1"),$1"' _ {} \;
    
  3. Третья команда:

    find *.txt -exec sh -c 'echo "$(sed -n "\$p" "$1"),$1"' _ {} \;
    

    Эта команда использует sed для извлечения последней строки файла. Как и в предыдущих случаях, необходимо изменить использование find. Например:

    find . -name "*.txt" -exec sh -c 'echo "$(sed -n "\$p" "$1"),$1"' _ {} \;
    

Каждый из этих вариантов имеет свои преимущества, и выбор можно сделать в зависимости от предпочтений к утилите (awk, tail или sed). Убедитесь, что используете правильный синтаксис для find, чтобы избежать ошибок в поиске файлов.

0

Ещё один способ сделать это выглядит следующим образом:

multiple_cmd() { 
    tail -n1 "$1" 
    ls "$1"
}
export -f multiple_cmd
find *.txt -exec bash -c 'multiple_cmd "$0"' {} \;

В одну строку это можно записать так:

multiple_cmd() { tail -1 "$1"; ls "$1"; }; export -f multiple_cmd; find *.txt -exec bash -c 'multiple_cmd "$0"' {} \;
  • multiple_cmd() — это функция.
  • export -f multiple_cmd — выполняет экспорт функции, чтобы другая подсистема могла ее видеть.
  • find *.txt -exec bash -c 'multiple_cmd "$0"' {} \; — команда find, которая будет выполнять функцию для ваших файлов.

Таким образом, функция multiple_cmd может быть такой длинной и сложной, как вам нужно.

0

Есть более простой способ:

find ... | while read -r file; do
    echo "посмотрите на мой $file, мой $file потрясающий";
done

Либо можно использовать:

while read -r file; do
    echo "посмотрите на мой $file, мой $file потрясающий";
done <<< "$(find ...)"

Таким образом, вы сможете обрабатывать файлы, найденные командой find, более компактным и элегантным способом.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь