Bash 复合子字符串扩展

Bash 复合子字符串扩展

我知道我可以用来awk解析多个分隔符,但这会产生子进程。我想知道复合/嵌套 bash 参数扩展是否可能。

我的 PDF 文件位于名为“Px_MM-DD-YY_SSSSSSSSSS.pdf”的目录中,其中:

  • “Px”表示“第 x 页”,并且 x 没有前导零。
  • “MM”对应于两位数月份,如果适用,则带有前导零。
  • “DD”对应两位数的日期,如果适用,则带有前导零。
  • “YY”对应两位数年份,如果适用,则带有前导零。
  • “SSSSSSSSSS”对应于创建 PDF 的十位数纪元时间,这允许我保留 PDF 页面修订。

我有一个 for 循环(当我准备好对所有 PDF 进行操作时,我会删除“-mtime”)

for file in $(find -type f -iname '*_??????????.pdf' -mtime -1)
do
    echo $file
done

我只想回显纪元时间。

我可以使用这个 for 循环

for file in $(find -type f -iname '*_??????????.pdf' -mtime -1)
do
    echo ${file##*_}
done

对于名为“./P14_07-21-18_4X_1532144458.pdf”的文件,“1532144458.pdf”会回显到屏幕上。

我可以使用这个 for 循环

for file in $(find -type f -iname '*_??????????.pdf' -mtime -1)
do
    echo ${file%.*}
done

对于名为“./P14_07-21-18_4X_1532144458.pdf”的文件,“./P14_07-21-18_4X_1532144458”会回显到屏幕上。

如果我echo ...用下面的任何格式替换该行

echo ${${file##*_}:0:10}
echo ${(${file##*_}):0:10}
echo ${${file##*_}%.*}
echo ${{file%.*}##_}
echo ${${file%.*}##_}

我明白了-bash: ... : bad substitution。我的语法是否正确,或者嵌套/复合 bash 扩展不可能?

答案1

您无法执行嵌套替换变量在最左边的部分。所以你可以做${foo#$bar},但不能做你所展示的。

如果您想在进一步的替换中使用替换结果,请将替换结果放入变量中。

答案2

如果不首先将初始结果保存到变量并对其应用第二次替换,则无法让参数替换对另一个参数替换的结果起作用。

您还可以循环输出find,其中不推荐

为循环提供结果的正确方法find是调用子 shell 并在其中执行循环:

find . -type f -iname '*_??????????.pdf' -mtime -1 -exec sh -c '
    for pathname do
        timestamp=${pathname##*_}   # remove up to last _
        timestamp=${timestamp%.pdf} # remove .pdf
        printf "pathname=%s\ttimestamp=%s\n" "$pathname" "$timestamp"
    done' sh {} +

这样,您就不必担心实际的路径名是什么。 Unix 中的文件名(即文件、目录和其他文件类型的名称)可以包含除 和 之外的任何字符/\0例如空格和换行符。通过在 上使用命令替换find,您可以强制 shell 首先执行分词(默认情况下在空格、制表符和换行符上),然后根据从 . 返回的路径名中找到的模式执行文件名生成find。因此,您的原始循环可能最终会循环与您预期完全不同的单词。

有关的:

答案3

如果我理解正确的话,使用 Awk 的问题在于您要为每个 PDF 文件调用一个 Awk 进程(我假设您有大量这样的文件)。

你可以按照以下方式运行一些东西

find . ...... -print0 | perl -0nE '/.*_(\d{10}).pdf/ and say "$1.pdf"'

或者如果你保持结构:

for file in $(find .....| perl ....)
do 
  ...
done

(当然,用任何 Awk、sed、Python 等效命令替换 Perl 命令)

(如果您有机会尝试这种方法请告诉我们time ....获得的结果)

相关内容