How can I refer back to arguments to coreutil's printf in no particular order?

This is what I want to avoid:

$ printf '%s %s %s %s %s %s %s' a c a c b c a
a c a c b c a

This is what I would like to do:

$ printf '%s %s³ %s¹ %s³ %s² %s³ %¹' a b c
a c a c b c a

This is how to do it with Perl.

perl -e 'printf ("%s %3\$s %1\$s %3\$s %2\$s %3\$s %1\$s\n", 'a', 'b', 'c');'
a c a c b c a

Notice only four arguments are passed to printf.

  • 2
    Is there a specific reason for using printf and not echo "[ -d $dir ] || mkdir $dir; cd $dir"? – terdon Jul 5 '13 at 16:37
  • Yes, but mine was a bad example. I rephrased the question so that I think it makes more sense now. – n.r. Jul 8 '13 at 1:49

There isn't a built-in way to do this that I was able to find. You can always generate the arguments in a loop like this:

for loop

$ printf '[ -d %s ] || mkdir %s; cd %s\n' `for run in {1..3}; do echo "$dir";done`

Slight variance:

$ printf '[ -d %s ] || mkdir %s; cd %s\n' $(for run in {1..3}; do echo "$dir";done)

You can control the number of arguments by changing this part of the command {1..3}.

seq & xargs

$ printf '[ -d %s ] || mkdir %s; cd %s\n' $(seq 1 3 | { xargs -i -- echo "$dir"; })

This will create a seq of numbers, 1 to 3, and this controls how many times the { xargs -i ... } will execute.


Thanks to @rici's comment you can also use this construct, yes ... | head -n 3:

$ printf '[ -d %s ] || mkdir %s; cd %s\n' $(yes "$dir" | head -n 3)


  • more concisely: $(yes "blah" | head -n 3)'. But neither that nor your answer will work if blah` contains $IFS characters. – rici Jul 5 '13 at 16:42
  • @rici - yeah I forgot to guard the strings with quotes, I've fixed that. Thanks for the yes ... | head ... construct. I was trying something with seq ... | { xargs ... } which is similar but your's is more compact. – slm Jul 5 '13 at 16:55

Printf in bash doesn't have that option implemented.

But a simple solution is to use variables:

$ a=a b=b c=c
$ printf '%s %s %s %s %s %s %s\n' "$a" "$c" "$a" "$c" "$b" "$c" "$a"
a c a c b c a

Or even the positional parameters:

$ set -- a b c
$ printf '%s %s %s %s %s %s %s\n' "$1" "$3" "$1" "$3" "$2" "$3" "$1"
a c a c b c a

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.