Вот свидетельство влияния опции -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.