2012-06-12 7 views
3

я заметил сегодня Bash printf имеет -v вариантprintf, игнорируя лишние аргументы?

-v var assign the output to shell variable VAR rather than 
      display it on the standard output 

Если я вызываю, как это работает

$ printf -v var "Hello world" 

$ printf "$var" 
Hello world 

Исходя из трубы не работает

$ grep "Hello world" test.txt | xargs printf -v var 
-vprintf: warning: ignoring excess arguments, starting with `var' 

$ grep "Hello world" test.txt | xargs printf -v var "%s" 
-vprintf: warning: ignoring excess arguments, starting with `var' 

ответ

8

xargs будет вызывать /usr/bin/printf (или там, где этот бинарный файл установлен в вашей системе). Он не будет ссылаться на встроенную функцию bash. И только встроенный (или источник сценария или аналогичный) может изменить среду оболочки.

Даже если это может вызвать встроенный bash, xargs в вашем примере работает в подмножестве. В любом случае подоболочка не может изменять среду своего родителя. Так что вы пытаетесь работать не можете.

Несколько вариантов, которые я вижу, если я правильно понимаю ваш образец; Выборочные данные:

$ cat input 
abc other stuff 
def ignored 
cba more stuff 

Простая переменная (немного сложнее в зависимости от того, что именно вы хотите):

$ var=$(grep a input) 
$ echo $var 
abc other stuff cba more stuff 
$ echo "$var" 
abc other stuff 
cba more stuff 

С массивом, если вы хотите отдельные слова в массивах:

$ var=($(grep a input)) 
$ echo "${var[0]}"-"${var[1]}" 
abc-other 

Или, если вам нужны целые строки в каждом элементе массива:

$ IFS=$'\n' var=($(grep a input)) ; unset IFS 
$ echo "${var[0]}"-"${var[1]}" 
abc other stuff-cba more stuff 
1

Есть два printf: один - это shell-бултин, и это вызывается, если вы просто запускаете printf, а другой - обычный двоичный файл, обычно/usr/bin/printf. Последнее не принимает аргумент -v, поэтому сообщение об ошибке. Поскольку printf является аргументом для xargs здесь, выполняется двоичный код, а не оболочка bulitin. Кроме того, поскольку он находится на приемной стороне конвейера, он запускается как подпроцесс. Переменные могут наследоваться только от родительского к дочернему процессу, но не наоборот, поэтому даже если двоичный файл printf может изменить среду, это изменение не будет отображаться в родительском процессе. Поэтому есть две причины, по которым ваша команда не может работать. Но вы всегда можете сделать var=$(something | bash -c 'some operation using builtin printf').

+0

Это не то, что это в конце конвейера это аргумент xargs, который принимает только внешние исполняемые файлы (который является '/ usr/bin/printf'). Кроме того, у вас нет результата, если вы не удалите '-v'. –

+0

@DennisWilliamson Вы правы, спасибо. Закрепление. –

0

Мат дает прекрасное объяснение того, что происходит и почему.

Если вы хотите перебрать выходе команды и установить переменный последовательные значения с помощью sprintf -style printf функции в Bash (-v), вы можете сделать это следующим образом:

grep "Hello world" test.txt | xargs bash -c 'printf -v var "%-25s" "[email protected]"; do_something_with_formatted "$var"' _ {} \; 
Смежные вопросы