循环目录并对 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,因为它完全意味着:

$男子重击 […] -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脚本循环

While循环重置Bash脚本中的数字变量[重复]

bash 脚本导航目录子结构,然后对 .xml 文件进行操作

PHP脚本循环遍历目录中的所有文件?

inotifywait 未在 bash 脚本中执行 while 循环

如何从脚本本身中获取 Bash 脚本的源目录?