Search code examples
bashshellprintfpiping

printf, ignoring excess arguments?


I noticed today Bash printf has a -v option

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

If I invoke like this it works

$ printf -v var "Hello world"

$ printf "$var"
Hello world

Coming from a pipe it does not work

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

Solution

  • xargs will invoke /usr/bin/printf (or wherever that binary is installed on your system). It will not invoke bash's builtin function. And only a builtin (or sourcing a script or similar) can modify the shell's environment.

    Even if it could call bash's builtin, the xargs in your example runs in a subsell. The subshell cannot modify it's parent's environment anyway. So what you're trying cannot work.

    A few options I see if I understand your sample correctly; sample data:

    $ cat input
    abc other stuff
    def ignored
    cba more stuff
    

    Simple variable (a bit tricky depending on what exactly you want):

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

    With an array if you want individual words in the arrays:

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

    Or if you want the whole lines in each array element:

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