Xargs с несколькими командами
В текущем каталоге я хотел бы напечатать имя файла и его содержимое.
Я могу печатать имена файлов или содержимое отдельно
find . | grep "file_for_print" | xargs echo
find . | grep "file_for_print" | xargs cat
но я хочу, чтобы они печатали их следующим образом:
file1
line1 inside file1
line2 inside file1
file2
line1 inside file2
line2 inside file2
Я читаю xargs с несколькими командами в качестве аргумента
и попробовал
find . | grep "file_for_print" | xargs -I % sh -c 'echo; cat;'
но не работает.
Я не знаком с xargs, поэтому не знаю, что именно означает "-I% sh -c".
Может ли кто-нибудь мне помочь? спасибо!
Ответы
Ответ 1
Для начала нет никакой разницы между:
find . | grep "file_for_print" | xargs echo
и
find . -name "file_for_print*"
за исключением того, что второй не будет соответствовать именам файлов, например this_is_not_the_file_for_print
, и он будет печатать имена файлов по одному в каждой строке. Это также будет намного быстрее, потому что ему не нужно создавать и печатать всю рекурсивную структуру каталогов только для того, чтобы grep удалял большую часть.
find . -name "file_for_print*"
на самом деле точно совпадает с
find . -name "file_for_print*" -print
где действие -print
печатает каждое совпадающее имя файла, за которым следует новая строка. Если вы не предоставляете find
любые действия, предполагается, что вы хотите -print
. Но у него больше трюков, чем у него. Например:
find . -name "file_for_print*" -exec cat {} \;
Действие -exec
приводит к тому, что find выполняет следующую команду, вплоть до \;
, заменяя {}
каждым соответствующим именем файла.
find
не ограничивается одним действием. Вы можете сказать, что делаете, сколько хотите. Итак:
find . -name "file_for_print*" -print -exec cat {} \;
вероятно, сделает все, что вам нужно.
Для получения дополнительной информации об этой очень полезной утилите введите:
man find
или
info find
и прочитайте все о нем.
Ответ 2
find . | grep "file_for_print" | xargs -I % sh -c 'echo %; cat %;'
(OP отсутствовал %
s)
Ответ 3
Так как еще не сказано: -I %
указывает xargs заменить "%" на аргументы в команде, которую вы ему даете. sh -c '...'
просто означает выполнение команд '...'
в новой оболочке.
So
xargs -I % sh -c 'echo %; cat %;'
будет выполняться echo [filename]
, за которым следует cat [filename]
для каждого имени файла, указанного в xargs
. Команды echo и cat будут выполняться внутри другого процесса оболочки, но это обычно не имеет значения. Ваша версия не работала, потому что в команде, переданной в xargs
, отсутствовали знаки %
.
Для чего я должен использовать эту команду для достижения того же:
find -name "*file_for_print*" | parallel 'echo {}; cat {};'
потому что он проще (parallel
автоматически использует {}
в качестве символа подстановки и может принимать несколько команд по умолчанию).
Ответ 4
Как написать собственную функцию bash?
#!/bin/bash
myFunction() {
while read -r file; do
echo "$file"
cat "$file"
done
}
find . -name "file_for_print*" | myFunction
Ответ 5
В этом конкретном случае каждая команда выполняется для каждого отдельного файла в любом случае, поэтому нет преимущества при использовании xargs. Вы можете просто добавить -exec дважды в свой "find":
find . -name "*file_for_print*" -exec echo {} \; -exec cat {} \;
В этом случае -print
можно использовать вместо первого echo
, как указано rici, но этот пример показывает возможность выполнения двух произвольных команд с помощью одного find