Как использовать -I{} с xargs' с -n больше 1?

Для сопоставления содержимого переменной оболочки в bash , zsh или ksh93 :

re='^[0-9]+(,[0-9]+)*$'
[[ $string =~ $re ]] && echo matches

POSIXly:

case $string in
  ("" | *[!,0-9]* | ,* | *, | *,,*) ;;
  (*) echo matches;;
esac

Bournely:

expr " $string" : ' [0-9]\{1,\}\(,[0-9]\{1,\}\)*$' > /dev/null &&
  echo matches

Для сопоставления строк ввода:

grep -xE '[0-9]+(,[0-9]+)*'

Мы используем + (или эквивалент BRE \ {1, \} ) для сопоставления 1 или более цифр. * соответствует 0 или более.

2
10.05.2019, 20:54
2 ответа

Да, -Iработает только с одним аргументом за раз. С -Iввод также разбирается на аргументы иначе, чем без (с использованием -nили без ).

С помощью -I{}вы получаете слово для каждой не -пустой строки (, за исключением того, что по-прежнему можно вставлять новую строку, заключая ее в кавычки с обратной косой чертой ), с начальными, но не конечными пробелами (список которых зависит от реализации и локали для некоторых удаленных ). Котировки (", 'и \по-прежнему обрабатываются, но не так, как shхотя ).

Без -I{}слова являются пробелами (, по крайней мере, с разделителями SPC, TAB и NL )и обрабатываются кавычки.

Сравните:

$ printf ' a "b c" \n' | xargs -n1 printf '<%s>\n'
<a>
<b c>
$ printf ' a "b c" \n' | xargs -I{} printf '<%s>\n' {}
<a b c >

IMO, xargs— это немного беспорядок, единственные надежные/полезные способы его использования — с расширениями -0и -dGNU.

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

xargs < filelist -r -n2 sh -c 'printf "1: %s\n2: %s\n" "$1" "$2"' sh

Здесь xargsпередает 2 аргумента за раз в sh, а shзанимает место, занимаемое "$1"и"$2"(см. также "$@"для передачи всех аргументов сразу ).

Это при токенизации слов по умолчанию xargs. Если filelistдолжен содержать один файл в строке, вы должны использовать -d '\n'GNU xargs.

Для вашего примера grepвам не нужны ни -n, ни -I, просто:

xargs < filelist grep mystring

Затем xargsпередаст как можно больше аргументов вgrep(аргументы добавляются в конце ). Мы можем обойтись без -rздесь (расширения GNU )как будто filelistвсе пустое, все еще работающее grepбез файловых аргументов (которое -rпредотвращает )должно быть безвредным, поскольку оно будет искать mystring в конце filelist.

Однако вы можете использовать параметр -HGNU grepили запустить его как:

xargs < filelist grep mystring /dev/null

, чтобы убедиться, что grepвсегда печатает имя файла, когда находит совпадение, даже если filelistсодержит только одно слово.

6
27.01.2020, 21:55

GNU Parallel исправил эту проблему. -X будет включать контекст:

$ seq 1 10 | parallel -j1 -qX echo "<{}>"
<1> <2> <3> <4> <5> <6> <7> <8> <9> <10>

-м не будет:

$ seq 1 10 | parallel -j1 -qm echo "<{}>"
<1 2 3 4 5 6 7 8 9 10>
0
27.01.2020, 21:55

Теги

Похожие вопросы