printf,忽略多余的论点?

时间:2012-06-12 20:03:46

标签: bash shell printf piping

我今天注意到Bash printf有一个-v选项

-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'

3 个答案:

答案 0 :(得分:8)

xargs将调用/usr/bin/printf(或在您的系统上安装二进制文件的任何位置)。它不会调用bash的内置函数。只有内置(或采购脚本或类似内容)才能修改sh​​ell的环境。

即使它可以调用bash的内置函数,您示例中的xargs也会在子集中运行。无论如何,子shell无法修改它的父级环境。所以你正在尝试的东西是行不通的。

如果我理解你的样本,我会看到一些选项;样本数据:

$ 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 :(得分:1)

有两个printf - 一个是shell bultin,如果你只运行printf而另一个是常规二进制文件,通常是/ usr / bin / printf,则调用它。后者不接受-v参数,因此出现错误消息。由于printfxargs的参数,因此运行二进制文件,而不是shell bulitin。此外,由于它位于管道的接收端,因此它作为子进程运行。变量只能从父进程继承到子进程,而不是相反,因此即使printf二进制文件可以修改环境,父进程也不会看到更改。因此,有两个原因导致您的命令无法工作。但你总是可以做var=$(something | bash -c 'some operation using builtin printf')

答案 2 :(得分:0)

Mat给出了正在发生的事情及其原因的绝佳解释。

如果要迭代命令的输出并使用Bash的sprintf - 样式printf功能(-v)将变量设置为连续值,则可以这样做:

grep "Hello world" test.txt | xargs bash -c 'printf -v var "%-25s" "$@"; do_something_with_formatted "$var"' _ {} \;