Предположим, у меня есть вывод команды (например, ls -1):
a
b
c
d
e
...
Я хочу применить команду (скажем echo) к каждому, по очереди. Например
echo a
echo b
echo c
echo d
echo e
...
Какой самый простой способ сделать это в bash?
Предположим, у меня есть вывод команды (например, ls -1):
a
b
c
d
e
...
Я хочу применить команду (скажем echo) к каждому, по очереди. Например
echo a
echo b
echo c
echo d
echo e
...
Какой самый простой способ сделать это в bash?
Ответы:
Это, вероятно, самый простой в использовании xargs. В твоем случае:
ls -1 | xargs -L1 echo
-LФлаг обеспечивает вход правильно читать. Со страницы руководства xargs:
-L number
Call utility for every number non-empty lines read.
A line ending with a space continues to the next non-empty line. [...]
lsавтоматически делает -1в трубе.
ls | xargs -L2 echoи ls -1 | xargs -L2 echoдает два разных выхода. Бывшее все на одной линии.
xargsможет запускать только исполняемые файлы, а не функции оболочки или встроенные команды оболочки. Для первых лучшим решением, вероятно, является решение с readпетлей.
-L1.
Вы можете использовать базовую операцию prepend в каждой строке:
ls -1 | while read line ; do echo $line ; done
Или вы можете направить вывод в sed для более сложных операций:
ls -1 | sed 's/^\(.*\)$/echo \1/'
sh: cho: not found a sh: cho: not foundпохоже, она принимает eв echo команду sed или что-то в этом роде.
whileцикл. cmd1 | while read line; do cmd2 $line; done, Или while read line; do cmd2 $line; done < <(cmd1)который не создает подоболочку. Это упрощенная версия вашей sedкоманды:sed 's/.*/echo &/'
"$line"цикл while, чтобы избежать разделения слов.
read -r lineчтобы не readиспортить экранированные символы. Например echo '"a \"nested\" quote"' | while read line; do echo "$line"; doneдает "a "nested" quote", который потерял свое вытекание. Если мы это сделаем, echo '"a \"nested\" quote"' | while read -r line; do echo "$line"; doneмы получим, "a \"nested\" quote"как ожидалось. См. Wiki.bash-hackers.org/commands/builtin/read
Вы можете использовать цикл for :
для файла в *; делать echo "$ file" сделано
Обратите внимание, что если рассматриваемая команда принимает несколько аргументов, то использование xargs почти всегда более эффективно, поскольку она вызывает только одну утилиту вместо нескольких раз.
printf '%s\0' * | xargs -0 ...- иначе, это довольно опасно с именами файлов с пробелами, кавычками и т. д.
Вы действительно можете использовать sed для этого, при условии, что это GNU sed.
... | sed 's/match/command \0/e'
Как это устроено:
cat /logs/lfa/Modified.trace.log.20150904.pw | sed -r 's/^(.*)(\|006\|00032\|)(.*)$/echo "\1\2\3 - ID `shuf -i 999-14999 -n 1`"/e'
for s in `cmd`; do echo $s; done
Если cmd имеет большой вывод:
cmd | xargs -L1 echo
cmdв выводе есть пробелы, первый потерпит неудачу.
Xargs не с обратными слешами, цитаты. Это должно быть что-то вроде
ls -1 |tr \\n \\0 |xargs -0 -iTHIS echo "THIS is a file."
опция xargs -0:
-0, --null Input items are terminated by a null character instead of by whitespace, and the quotes and backslash are not special (every character is taken literally). Disables the end of file string, which is treated like any other argument. Useful when input items might contain white space, quote marks, or backslashes. The GNU find -print0 option produces input suitable for this mode.
ls -1завершает элементы символами новой строки, поэтому trпереводит их в нулевые символы.
Этот подход примерно в 50 раз медленнее, чем итерация вручную for ...(см. Ответ Майкла Аарона Сафяна) (3,55 с против 0,066 с). Но для других команд ввода, таких как locate, find, чтение из файла ( tr \\n \\0 <file) или аналогичных, вы должны работать с xargsэтим.
Лучший результат для меня:
ls -1 | xargs -L1 -d "\n" CMD
find . -mindepth 1 -maxdepth 1 -print0 | xargs -0 commandбудет обрабатывать случаи, когда вывод ls -1неоднозначен; используйте, -printf '%P\0'а не -print0если вы не хотите ведущий ./на каждом.
ls -1может быть примером здесь, но важно помнить, что не очень хорошо разбирать выводls. См .: mywiki.wooledge.org/ParsingLs