循环目录并对 bash 脚本中的文件进行操作
Posted
技术标签:
【中文标题】循环目录并对 bash 脚本中的文件进行操作【英文标题】:Loop over directories and act on files in bash script 【发布时间】:2018-06-28 19:37:06 【问题描述】:我有一个脚本 /home/user/me/my_script.sh 应该循环多个目录并处理文件。我当前的工作目录是/home/user/me。调用 ls -R 产生:
./项目:
dir1 dir2 dir3
./projects/dir1:
image1.ntf points2.csv image1.img image1.hdr
./projects/dir2:
image2.ntf points2.csv image2.img image2.hdr
./projects/dir3:
image3.ntf points3.csv image3.img image3.hdr
我有这个脚本:
#! /bin/bash -f
for $dir in $1*
do
echo $dir
set cmd = `/home/tools/tool.sh -i $dir/*.ntf -flag1 -flag2 -flag3 opt3`
$cmd
done
这是它的运行方式(来自 cwd /home/user/me)和结果:
bash-4.1$ ./myscript.sh projects/
projects/*
bash-4.1$
这不是预期的输出。预期的输出是:
bash-4.1$ ./myscript.sh projects/
projects/dir1
[output from tool.sh]
projects/dir2
[output from tool.sh]
projects/dir3
[output from tool.sh]
bash-4.1$
脚本应该进入第一个目录,找到 *.ntf 文件并将其传递给 tool.sh。那时我会开始看到该工具的输出。我已在单个文件上运行该工具:
bash-4.1$ /home/tools/tool.sh -i /home/user/me/projects/dir1/image1.ntf -flag1 -flag2 -flag3 opt3
[expected output from tool. lengthy.]
bash-4.1$
我尝试过在这里找到的语法:How to loop over directories in Linux? 和这里:Looping over directories in Bash
for $dir in /$1*/
do ...
结果:
bash-4.1$ ./myscript.sh projects/
/projects/*/
还有:
for $dir in $1/*
do ...
结果:
bash-4.1$ ./myscript.sh projects
projects/*
我不确定我还能想出多少其他的通配符和斜线迭代。正确的语法是什么?
【问题讨论】:
tool.sh
的冗长预期输出是一组命令,还是其他一些输出?
这是关于工具在过程中的位置的文本输出。它需要一个 *.ntf 文件并对图像执行多次计算以生成校准图像。处理大图像可能需要几分钟时间,因此此输出可让用户了解进度。
所以..您似乎正在尝试将变量 $cmd
设置为脚本的输出,然后像运行命令一样运行该输出。你对这个变量的意图是什么?为什么不直接运行该工具? (请随时通过澄清您的问题而不是 cmets 来回答。)
顺便说一句,shellcheck.net 会自动捕获至少一部分问题。
【参考方案1】:
首先,您应该删除 shebang 中的标志 -f
,因为它完全意味着:
其次,有一些典型的错误模式:变量周围缺少空格(写"$dir"
以应对包含空格的目录名),在你的for
行中有一个虚假的$
(写for dir in "$1"*
)代替,set
行不正确(set
是内置的 shell,仅用于更改 shell 的配置,例如set -x
),根据您对@ghoti 问题的回答,$cmd
行似乎是不必要。此外,反引号语法已被弃用,可能已替换为 cmd=$(/home/tools/tool.sh -i "$dir"/*.ntf -flag1 -flag2 -flag3 opt3)
。
这将导致以下脚本:
#!/bin/bash 对于“$ 1”中的目录* 做 [[ -d "$dir" ]] || continue # 只考虑现有文件夹 printf "%s=%q\n" dir "$dir" /home/tools/tool.sh -i "$dir"/*.ntf -flag1 -flag2 -flag3 opt3 完毕顺便说一句,我建议始终在 Bash 脚本上运行 ShellCheck 静态分析器,以便检测典型错误并获得 w.r.t 的反馈。良好做法。如果你有 Linux 发行版,它应该是可安装的 with your standard package manager。
【讨论】:
"$1"*/
,如果您只想将目录作为全局结果。否则文件也会出现。也可以在循环中使用[[ -d "$dir" ]] || continue
——这也可以解决不存在目录的情况,这样你就可以得到一个返回文字*
的字符串,而不需要nullglob
。
确实,@CharlesDuffy(谢谢!)我刚刚在我的回答中添加了你的第二个建议。
...哦,可能想在printf
格式字符串的末尾添加一个\n
。 (看起来像是我可能写过的东西——如果这个想法来自我,我深表歉意!)
谢谢你,这行得通!今后我将广泛使用 ShellCheck。我经常从其他人的脚本中构建新的脚本,所以旧的做法在不应该的时候得到了传播。以上是关于循环目录并对 bash 脚本中的文件进行操作的主要内容,如果未能解决你的问题,请参考以下文章
bash 脚本导航目录子结构,然后对 .xml 文件进行操作