这更多的是对 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
文件名并构造上面的命令?
要求
- 答案需要采用 bash 命令或更好的 Makefile 目标定义的形式;
- 默认情况下它需要在大多数 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 分隔的文件名列表并将它们传递给make
via 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+"$@"}