Expand glob with flag inserted before each filename

Using printf and an xargs supporting nul-delimited input:

printf -- '-f\0%s\0' important-files/*.txt | xargs -0 prog

printf loops the format string over the arguments, so for each filename in the expansion of the glob, it will print -f and the filename separated by the null character. xargs then reads this and converts it into arguments for prog. The -- needed since some implementations of printf have trouble with a leading - in the format string. Alternately, the - can be replaced with \055, which is standard.

Same principle as Rakesh's answer, but using the wildcard expansion directly.


With bash, try:

args=()
for f in important-files/*.txt
do
    args+=(-f "$f")
done
prog "${args[@]}"

Note that this will work not merely with filenames that contain blanks but also with filenames that contain single or double quotes or even newlines.

Easy interactive use

For easy interactive use, define a function:

progf() { args=(); for f in  "$@"; do args+=(-f "$f"); done; prog "${args[@]}"; }

This function can be used as follows:

progf important-files/*.txt

To make the function definition permanent, place it in your ~/.bashrc file.


zsh now has a P glob qualifier for that.

For older versions, you can always use:

f=(*.txt)
prog -f$^f

$^f enables the rcexpandparam option for the expansion of $f, where arrays are expanded in a style similar to that of the rc shell.

In rc (or zsh -o rcexpandparam):

f=(*.txt)
prog -f$f

Is expanded to prog -fa.txt -fb.txt, a bit as if you had written in csh (or other shells supporting brace expansion): prog -f{a.txt,b.txt}.

(note that it's different from *.txt(P:-f:) in that the file name is glued to the option -ffile.txt as opposed to passing two arguments -f file.txt. Many commands including all those that use the standard getopt() API to parse options support both ways passing arguments to options).

fish also expands arrays like that:

set f *.txt
prog -f$f

In bash, you can emulate it with:

f=(*.txt)
prog "${f[@]/#/-f}"

With ksh93:

f=(*.txt)
prog "${f[@]/*/-f\0}"

For -f and the corresponding file.txts to be passed as separate arguments, another option with zsh using its array zipping operator:

o=-f f=(*.txt); prog ${o:^^f}

You could extend that for your -g option. Assuming there's an even number of txt files:

o=(-g '') f=(*.txt); prog ${o:^^f}

Would pass -g options with two files at a time. Similar to what you'd get with:

printf -- '-g\0%s\0%s\0' *.txt | xargs -r0 prog

Tags:

Bash

Wildcards