Выводит ли `xargs -t` stderr или stdout, и можете ли вы этим управлять?
-
20-08-2019 - |
Вопрос
допустим, у меня есть каталог с hi.txt и blah.txt и я выполняю следующую команду в командной строке Linux
ls *.* | xargs -t -i{} echo {}
результат, который вы увидите, это
echo blah.txt
blah.txt
echo hi.txt
hi.txt
я бы хотел перенаправить вывод stderr (скажем, "echo blah.txt" не удается ...), оставляя только выходные данные команды xargs -t написано в std out, но выглядит так, как будто это тоже stderr.
ls *.* | xargs -t -i{} echo {} 2> /dev/null
Есть ли способ управлять этим, чтобы вывести его в стандартный вывод?
Решение
Поэтому я верю, что то, что вы хотите, - это иметь в качестве стандартного вывода
- стандартный вывод из утилиты, которую выполняет xargs
- список команд , сгенерированных xargs -t
Вы хотите игнорировать поток stderr, сгенерированный выполняемой утилитой.
Пожалуйста, поправьте меня, если я ошибаюсь.
Во-первых, давайте создадим лучшую утилиту тестирования:
% cat myecho
#!/bin/sh
echo STDOUT $@
echo STDERR $@ 1>&2
% chmod +x myecho
% ./myecho hello world
STDOUT hello world
STDERR hello world
% ./myecho hello world >/dev/null
STDERR hello world
% ./myecho hello world 2>/dev/null
STDOUT hello world
%
Итак, теперь у нас есть что-то, что фактически выводит как в stdout, так и в stderr, так что мы можем быть уверены, что получаем только то, что хотим.
Тангенциальный способ сделать это - не использовать xargs, а скорее make.Повторение команды а затем выполнение - это вроде того, что делает make.Это его сумка.
% cat Makefile
all: $(shell ls *.*)
$(shell ls): .FORCE
./myecho $@ 2>/dev/null
.FORCE:
% make
./myecho blah.txt 2>/dev/null
STDOUT blah.txt
./myecho hi.txt 2>/dev/null
STDOUT hi.txt
% make >/dev/null
%
Если вы привязаны к использованию xargs, то вам нужно модифицировать вашу утилиту, которую
использует xargs, чтобы она превосходила stderr.Затем вы можете использовать 2>&1
хитрость других
упоминалось переместить список команд, сгенерированный xargs -t, из stderr
в стандартный вывод.
% cat myecho2
#!/bin/sh
./myecho $@ 2>/dev/null
% chmod +x myecho2
% ./myecho2 hello world
STDOUT hello world
% ls *.* | xargs -t -i{} ./myecho2 {} 2>&1
./myecho blah.txt 2>/dev/null
STDOUT blah.txt
./myecho hi.txt 2>/dev/null
STDOUT hi.txt
% ls *.* | xargs -t -i{} ./myecho2 {} 2>&1 | tee >/dev/null
%
Таким образом, этот подход работает и сворачивает все, что вы хотите вывести из стандартного режима (исключая то, что вам не нужно).
Если вы обнаружите, что часто этим занимаетесь, вы можете написать общую утилиту для surpress stderr:
% cat surpress_stderr
#!/bin/sh
$@ 2>/dev/null
% ./surpress_stderr ./myecho hello world
STDOUT hello world
% ls *.* | xargs -t -i{} ./surpress_stderr ./myecho {} 2>&1
./surpress_stderr ./myecho blah.txt 2>/dev/null
STDOUT blah.txt
./surpress_stderr ./myecho hi.txt 2>/dev/null
STDOUT hi.txt
%
Другие советы
Использование:
ls | xargs -t -i{} echo {} 2>&1 >/dev/null
В 2>&1
отправляет стандартную ошибку из xargs
туда, куда в данный момент направляется стандартный вывод;в >/dev/null
отправляет исходный стандартный вывод на /dev/null
.Итак, конечным результатом является то, что стандартный вывод содержит команды echo, и /dev/null
содержит имена файлов.Мы можем спорить о пробелах в именах файлов и о том, было бы проще использовать sed
скрипт для размещения 'echo' в начале каждой строки (без -t
вариант), или могли бы вы использовать:
ls | xargs -i{} echo echo {}
(Проверено:Solaris 10, Оболочка Korn ;должен работать на других оболочках и платформах Unix.)
Если вы не возражаете посмотреть на внутреннюю работу команд, мне удалось отделить вывод ошибки от xargs
и вывод ошибки выполненной команды.
al * zzz | xargs -t 2>/tmp/xargs.stderr -i{} ksh -c "ls -dl {} 2>&1"
(Нестандартная) команда al
перечисляет его аргументы по одному в строке:
for arg in "$@"; do echo "$arg"; done
Первое перенаправление (2>/tmp/xargs.stderr
) отправляет вывод с ошибкой из xargs
к файлу /tmp/xargs.stderr
.Выполняемая команда является 'ksh -c "ls -dl {} 2>&1"
', который использует оболочку Korn для запуска ls -ld
по имени файла с любым выводом ошибки, переходящим к стандартному выводу.
Результат в /tmp/xargs.stderr
выглядит как:
ksh -c ls -dl x1 2>&1
ksh -c ls -dl x2 2>&1
ksh -c ls -dl xxx 2>&1
ksh -c ls -dl zzz 2>&1
Я использовал 'ls -ld
" вместо echo
чтобы убедиться, что я тестировал ошибки - файлы x1
, x2
, и xxx
существовал, но zzz
не делает этого.
Вывод на стандартный вывод выглядел следующим образом:
-rw-r--r-- 1 jleffler rd 1020 May 9 13:05 x1
-rw-r--r-- 1 jleffler rd 1069 May 9 13:07 x2
-rw-r--r-- 1 jleffler rd 87 May 9 20:42 xxx
zzz: No such file or directory
При запуске без команды , завернутой в 'ksh -c "..."
', перенаправление ввода-вывода было передано в качестве аргумента команде ('ls -ld
'), и поэтому он сообщил, что не смог найти файл '2>&1
'.Это, xargs
сам не использовал оболочку для выполнения перенаправления ввода-вывода.
Можно было бы организовать различные другие перенаправления, но основная проблема заключается в том, что xargs
не предусматривает отделения своего собственного вывода ошибок от вывода команд, которые он выполняет, поэтому это трудно сделать.
Другой довольно очевидный вариант - использовать xargs
написать сценарий оболочки, а затем заставить оболочку выполнить его.Это тот вариант, который я показывал ранее:
ls | xargs -i{} echo echo {} >/tmp/new.script
Затем вы можете просмотреть команды с помощью:
cat /tmp/new.script
Вы можете запустить команды для удаления ошибок с помощью:
sh /tmp/new.script 2>/dev/null
И, если вы также не хотите видеть стандартный вывод команд, добавьте 1>&2
до конца выполнения команды.
xargs -t
повторяет команды, которые должны быть выполнены, в stderr перед их выполнением.Если вы хотите, чтобы они вместо этого передавали эхо в stderr, вы можете передать stderr в stdout с помощью 2>&1
сконструировать:
ls *.* | xargs -t -i{} echo {} 2>&1
Похоже, что xargs -t переходит в stderr, и вы мало что можете с этим поделать.
Вы могли бы сделать:
ls | xargs -t -i{} echo "Foo: {}" >stderr.txt | tee stderr.txt
чтобы отобразить только данные stderr на вашем терминале при выполнении вашей команды, а затем выполнить grep через stderr.txt после, чтобы увидеть, произошло ли что-нибудь неожиданное, в соответствии с grep -v Foo: stderr.txt
Также обратите внимание, что в Unix, ls *.*
это не то, как вы все показываете.Если вы хотите просмотреть все файлы, просто запустите ls
само по себе.
Насколько я понимаю, ваша проблема заключается в использовании GNU Parallel http://www.gnu.org/software/parallel/ поступил бы правильно:
ls *.* | parallel -v echo {} 2> /dev/null