STDOUT 作为 bash / Makefile 中的参数并正确处理空间

STDOUT 作为 bash / Makefile 中的参数并正确处理空间

这更多的是对 bash 语法的心理练习。我邀请你把这个当作一个谜题,这样我们就可以一起解决这个问题。或者作为理解 bash 的挑战。

问题

例如,我的文件夹中有 3 个文件./etc

  • ./etc
    • foo.txt.example
    • bar.txt.example
    • hello world.txt.example (是的,这个文件中有空间)

我已经构建了目标来执行这些目标,基于上述文件,有效:

make "etc/foo.txt"
make "etc/bar.txt"
make "etc/hello world.txt"

所以理论上,我可以构建这样的命令来运行所有目标:

make "etc/foo.txt" "etc/bar.txt" "etc/hello world.txt"

我的问题来了:你能构建一个 bash 脚本来搜索所有内容吗 ./etc/*.txt.example 文件名并构造上面的命令?

要求

  1. 答案需要采用 bash 命令或更好的 Makefile 目标定义的形式;
  2. 默认情况下它需要在大多数 Linux 环境中运行。它不应该需要安装不常见的软件包。

我尝试过的

我已经在 Makefile 中找到了一种获取上面所有文件名的方法:

txt:
    for fn in "etc/*.txt.example"; do \
        echo "etc/$$(basename -s ".example" "$$fn")"; \
    done

这基本上意味着在 bash 中运行它:

for fn in "etc/*.txt.example"; do \
    echo "etc/$(basename -s ".example" "$fn")"; \
done

给出以下输出:

etc/foo.txt
etc/bar.txt
etc/hello world.txt

如果您使用此循环的输出作为另一个命令的输入,该命令似乎将所有空格视为参数的分隔符。所以这:

make $(for fn in "etc/*.txt.example"; do \
    echo "etc/$(basename -s ".example" "$fn")"; \
done)

实际上是这样的:

make "etc/foo.txt" "etc/bar.txt" "etc/hello" "world.txt"

有没有办法将循环的输出转换为正确保留空格的争论?

答案1

您可以使用数组:

# Get all example files in an array
examples=(etc/*.example)
# Strip the .example suffix from every element of the array
make "${examples[@]%.example}"

或者,如果您有 GNU find、sed 和 xargs(即支持 nul 分隔符):

find etc -iname '*.example' -print0 | sed -z 's/\.example$//' | xargs -0 make

答案2

创建一个以 nul 分隔的文件名列表并将它们传递给makevia xargs

for name in /etc/*.txt.example; do
    printf '%s\0' "${name%.example}"
done | xargs -0 make

答案3

首先创建示例文件,然后创建

set etc/*.tbl.example
N="shift $#"
for arg
do
   $N; N=;
   set X ${1+"$@"} "$(expr "$arg" '\(.*\).example')"; shift       
done
# and then...
make ${1+"$@"}

相关内容