Почему код выхода xargs отличается в зависимости от наличия опции "-I"? - PullRequest
0 голосов
/ 10 апреля 2019

После прочтения справочной страницы xargs я не могу понять разницу в кодах выхода из следующих вызовов xargs.

(Первоначальная цель состояла в том, чтобы объединить поиск и grep для проверкиесли выражения существуют во ВСЕХ указанных файлах, когда я сталкивался с этим поведением)

Воспроизвести:

(используйте >>!, если для создания файла используется zsh)

# Create the input files.
echo "a" >> 1.txt   
echo "ab" >> 2.txt

# The end goal is to check for a pattern (in this case simply 'b') inside
# ALL the files returned by a find search. 
find .  -name "1.txt" -o -name "2.txt" | xargs -I {}  grep -q "b"  {}
echo $?
  123  # Works as expected since 'b' is not present in 1.txt

find .  -name "1.txt" -o -name "2.txt" | xargs grep -q "b"
echo $?
  0   # Am more puzzled by why the behaviour is inconsistent

В разделе EXIT_STATUS на странице руководства написано:

xargs exits with the following status:
0 if it succeeds
123 if any invocation of the command exited with status 1-125
124 if the command exited with status 255
125 if the command is killed by a signal
126 if the command cannot be run
127 if the command is not found
1 if some other error occurred.

Я бы подумал, что 123 if any invocation of the command exited with status 1-125 должен применяться независимо от того, используется ли -I?

Не могли бы вы поделиться своими соображениями, чтобы объяснить эту загадку, пожалуйста?

1 Ответ

0 голосов
/ 10 апреля 2019

Вот свидетельство влияния опции -I на xargs с помощью скрипта-обёртки, который показывает количество вызовов:

cat ./grep.sh
#/bin/bash

echo "I am being invoked at $(date +%Y%m%d_%H-%M-%S)"
grep $@

(фактическая вызываемая команда, в данном случае grep не имеет значения)

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

❯ find .  -name "1.txt" -o -name "2.txt" | xargs -I {}  ./grep.sh -q "b" {}
I am being invoked at 20190410_09-46-29
I am being invoked at 20190410_09-46-30

❯ find .  -name "1.txt" -o -name "2.txt" | xargs ./grep.sh -q "b"
I am being invoked at 20190410_09-46-53

Я только что обнаружил комментарий к ответу на аналогичный вопрос, который отвечает на этот вопрос (полная оценка https://superuser.com/users/49184/daniel-andersson за его мудрость):

https://superuser.com/questions/557203/xargs-i-behaviour#comment678705_557230

Кроме того, пробелы без кавычек не завершают элементы ввода; вместо этого разделителем является символ перевода строки. - это главное для понимания поведения. Без -I xargs видит входные данные только как одно поле, поскольку символ новой строки не является разделителем полей. С -I неожиданно новая строка становится разделителем полей, и, таким образом, xargs видит три поля (по которым он перебирает). Это очень тонкий момент, но он объясняется в цитированной справочной странице.

-I replace-str
   Replace occurrences of replace-str in the initial-arguments
   with names read from standard input.  Also, unquoted blanks do
   not terminate input items; instead the separator is the
   newline character.  Implies -x and -L 1.

Исходя из этого,

find .  -name "1.txt" -o -name "2.txt"  
#returns
# ./1.txt 
# ./2.txt

xargs -I {}  grep -q "b"  {}
# interprets the above as two separate lines since,
# with -I option the newline is now a *field separator*. 
# So this results in TWO invocations of grep and since one of them fails, 
# the overall output is 123 as documented in the EXIT_STATUS section

xargs grep -q "b"
# interprets the above as a single input field,
# so a single grep invocation which returns a successful exit code of 0 since the pattern was found in one of the files.
...