Выводит ли `xargs -t` stderr или stdout, и можете ли вы этим управлять?

StackOverflow https://stackoverflow.com/questions/842401

  •  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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top