返回与 shell glob 匹配相对应的字符串

返回与 shell glob 匹配相对应的字符串

假设我有一个名为 的子目录sub。然后我想对该目录中扩展名为“txt”的所有文件进行操作。我想要类似的东西

for f in sub/*.txt
do
    enscript -b "" -o {$f basename excluding .txt}.ps sub/{$f basename excluding .txt}.txt                                                                                                                             
    ps2pdf {$f basename excluding .txt}.ps {$f basename excluding .txt}.pdf
done

sub因此,如果表单的目录中只有一个文件*.txt,例如sub/foo.txt,脚本应扩展为

enscript -b "" -o foo.ps sub/foo.txt                                                                                                                                   
ps2pdf foo.ps foo.pdf

我通常更喜欢便携式解决方案,但了解不同的做事方式总是很有趣。所以非便携式也可以,请说明您的解决方案是便携式还是非便携式。另外,标题可能不是最好的,所以请随意修改。

编辑:我意识到所写的示例不太有意义,因为它foo.txt位于sub目录中,因此sub/foo.txt需要传递到enscript.我还将 -penscript选项更改为更标准的-o选项。

答案1

POSIX shell(例如,bash、dash、ksh 等)接受${var%suffix}可用于从变量值中删除尾部部分的构造。例如,如果path="sub/file.txt",则${path%.txt} 扩展为sub/file

有一个对称构造可以删除前缀:${var#prefix}。前缀可以是一个模式。将#最长的匹配前缀加倍。例如, if path=sub/dir/file.txt, then${path##*/}扩展为file.txt(并${path#*/}扩展为dir/file.txt)。后缀 和 也是如此%

因此,在您的情况下,您可以这样写(请注意,您不能将前缀剥离和后缀剥离合并到单个扩展中,至少不能仅使用 POSIX 构造):

for f in sub/*.txt; do
  base=${f%.txt}
  base=${base##*/}
  enscript -b "" -o "$base.ps" "$f"
  ps2pdf "$base.ps" "$base.pdf"
done

或者,GNU 基本名称命令接受可选的第二个参数,它是要删除的文件扩展名。例如,如果$ffile.txt,则$(basename $f .txt)扩展为 file

但请注意,这basename会删除除最后一个组件之外的所有路径信息,因此如果您只想删除扩展名,则必须将其放回去(请参阅 目录名命令)。

答案2

可移植的方法是使用 和 剥离扩展名${f%.*}和目录${f##*/}(或使用basename

在zsh中,您可以申请各种变换参数扩展, 包括历史修改器例如r剥离一个扩展名和t剥离目录部分。

for x in sub/*.txt; do
    enscript -b "" -o ${x:t:r}.ps $x
    ps2pdf ${x:t:r}.ps ${x:t:r}.pdf
done

您可以将历史修改器应用到全局模式以及。

for x in sub/*.txt(:r:t); do
    enscript -b "" -o $x.ps sub/$x.txt
    ps2pdf $x.ps $x.pdf
done

相关内容