扩展 glob,并在每个文件名之前插入标志

扩展 glob,并在每个文件名之前插入标志

我有一个程序需要以下语法的参数:

prog [-f filename | -g filename1 filename2] ...

每个文件名必须以该标志为前缀-f。例如,以下是有效的调用prog

prog -f a.txt -g b.txt c.txt -f d.txt
prog -g a.txt b.txt -g c.txt d.txt
prog -f a.txt -f b.txt -f c.txt

…但以下不是:

prog -f a.txt b.txt
prog -f a.txt -g b.txt
prog a.txt

就我而言,我只关心-f选择。

我的目录中有很多文件,所有文件都以.txt.它们看起来像这样:

important-files/
├── a.txt
├── b.txt
├── c.txt
├── d.txt
└── filename with spaces.txt

我想避免需要一一列出每个文件。通常,我会使用一个简单的 glob 来实现:

$ prog important-files/*.txt

但这不起作用,因为它会产生以下无效调用:

$ prog important-files/a.txt important-files/b.txt important-files/c.txt important-files/d.txt 'important-files/filename with spaces.txt'

......当我真的想要这个调用时:

$ prog -f important-files/a.txt -f important-files/b.txt -f important-files/c.txt -f important-files/d.txt -f 'important-files/filename with spaces.txt'

…因为每个文件名必须以 为前缀,-f以便prog理解它们不应该被解释为-g.

使用 glob 并为其扩展的每个文件添加标志的最短方法是什么?

答案1

使用printfxargs支持空分隔输入:

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

printf在参数上循环格式字符串,因此对于 glob 扩展中的每个文件名,它将打印-f并用空字符分隔文件名。xargs然后读取它并将其转换为 的参数prog。这是--必需的,因为某些实现在格式字符串中printf存在前导问题。-或者,-可以替换为\055,这是标准的。

原理与拉克什的回答,而是直接使用通配符扩展。

答案2

zsh现在有一个Pglob 限定符

对于旧版本,您始终可以使用:

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

$^f使rcexpandparam选项对于 的扩展$f,其中数组以类似于 shell 的方式扩展rc

rc(或zsh -o rcexpandparam)中:

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

扩展为prog -fa.txt -fb.txt,有点像您在 csh(或其他支持大括号扩展的 shell)中编写的:prog -f{a.txt,b.txt}

(请注意,它的不同之处*.txt(P:-f:)在于文件名粘在选项上,-ffile.txt而不是传递两个参数-f file.txt。许多命令,包括所有使用标准getopt()API 来解析选项的命令,都支持将参数传递给选项的两种方式)。

fish还可以像这样扩展数组:

set f *.txt
prog -f$f

在 中bash,您可以通过以下方式模拟它:

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

ksh93

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

对于-f和 相应的file.txts 作为单独的参数传递,另一个选项是zsh使用其数组压缩运算符:

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

您可以根据您的-g选择扩展该范围。假设有偶数个txt文件:

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

-g一次会传递两个文件的选项。与您得到的类似:

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

答案3

使用 bash,尝试:

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

请注意,这不仅适用于包含空格的文件名,也适用于包含单引号或双引号甚至换行符的文件名。

轻松互动使用

为了方便交互使用,定义一个函数:

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

该函数可以如下使用:

progf important-files/*.txt

要使函数定义永久存在,请将其放入~/.bashrc文件中。

答案4

一。方法是使用 GNU find/xargs duo:

cd important-files && \
find . -name '*.txt'  -printf '-f\0%p\0' | xargs -0 -r  prog

相关内容