如何在Linux终端中循环执行可执行命令?

19

首先让我描述一下我的情况,我正在Linux平台上工作,并且有一组.bmp文件,它们的文件名从filename0022.bmp递增到filename0680.bmp。总共有658张图片。我想能够将每张图片传递给一个运行在.exe文件中的程序来处理,然后将输出文件发送到用户指定的文件夹中,该程序还有一些阈值参数:lower、upper。因此,这个可执行文件的典型调用方式是:

./filter inputfile outputfile lower upper

是否有一种方法可以通过终端或创建某种bash脚本循环调用所有文件?我的问题类似于这个问题:使用批处理文件在多个文件上执行命令,但这次我是在Linux命令行终端中工作。

6个回答

17

你可能会有兴趣学习bash脚本。

你可以直接从shell中执行for循环中的命令。

一个简单的循环可以生成你具体提到的数字。例如,从shell中:

user@machine $ for i in {22..680} ; do
> echo "filename${i}.bmp"
> done

这将为您提供从filename22.bmpfilename680.bmp的列表。 这只是处理您提到的范围迭代的简单方法。这不涵盖零填充数字。 为此,您可以使用printfprintf语法为printf格式参数。 我们可以将先前循环中的$i变量用作参数,并应用%Wd格式,其中W是宽度。 在W占位符前加上前缀将指定要使用的字符。 例如:

user@machine $ for i in {22..680} ; do
> echo "filename$(printf '%04d' $i).bmp"
> done

在上述代码中,$() 充当变量的角色,执行命令以获取与预定义值相反的值。

现在这应该可以给您所指定的文件名。我们可以将其应用于实际应用程序:

user@machine $ for i in {22..680} ; do
> ./filter "filename$(printf '%04d' $i).bmp" lower upper
> done

这可以重写成一行:

user@machine $ for i in {22..680} ; do ./filter "filename$(printf '%04d' $i).bmp" lower upper ; done

需要注意的是,从问题中可以看出,.exe文件通常是以COFF格式编译的,而Linux则需要一个ELF格式的可执行文件。


user@machine $ 是模拟 shell 提示符,而 > 则表示提示符继续等待更多命令输入才能执行。 - Steve Buzonas

14

这里有一个简单的例子:

for i in {1..100}; do echo "Hello Linux Terminal"; done

追加内容到文件中:(使用 >> 进行追加,你也可以使用 > 进行覆盖)

for i in {1..100}; do echo "Hello Linux Terminal" >> file.txt; done

8
您可以尝试像这样的方法...
#! /bin/bash
for ((a=022; a <= 658 ; a++))
do
   printf "./filter filename%04d.bmp outputfile lower upper" $a | "sh"
done

1
这是我尝试过的代码,它在屏幕上打印了一堆相关的内容,但实际上并没有创建任何文件...#! /bin/bash for ((a=022; a<=680; a++)) do printf "./filter fetus-00-2.3.5um__voi0%04d.bmp fetus_threshold_%04d 90 240" $a done其中90和240是我之前提到的下限和上限参数。我还没有创建bash脚本,所以我只是使用emacs创建了一个文件,在其中输入了上述代码行。然后,我将emacs文件简单地保存为test.,因为我在网上看到了一些示例这样做。有什么进一步的建议吗? - Linux Rules
尝试将其制作成一个.sh文件(包括我上面新增的内容),然后在相同目录下键入[[bash myfile.sh]]来运行该文件。 - scottyaz
好消息是,这次它至少迭代了,并且甚至在第一张图像上工作了,然后我得到了一些来自可执行文件使用的软件的错误。我不理解的是,它试图从inputfile0000开始启动,而我们告诉它从inputfile0022.bmp开始启动。唯一得到的输出图像是outputfile0000.bmp。这里是我保存为threshold.sh的bash文件:#! /bin/bashfor ((a=022; a<= 680; a++)) do printf "./filter6 fetus-00-2_3.5um__rec_voi%04d.bmp fetus_threshold_%04d.bmp 90 240" $a | "sh" done - Linux Rules
我不确定出了什么问题,但我看到一个问题...在printf语句中的每个引用中,您需要提供一个参数(即您应该有$a $a而不仅仅是一个)。 - scottyaz
耶哈!!!成功了!!!尽管我设置了a=22,但它仍然试图从input0000.bmp开始启动,不知何故。如果我厌倦了抛出21个异常,我可以编写一小段简单的代码来更改文件名以从0开始启动。感谢您的帮助。 - Linux Rules

2
您可以利用xargs进行迭代:
ls | xargs -i ./filter {} {}_out lower upper

注意:

  • {} 对应管道中的一行输出,这里是输入文件名。
  • 输出文件将以后缀“_out”命名。

1

您可以在您的 shell 中测试 AS-IS

for i in *; do
    echo "$i" | tr '[:lower:]' '[:upper:]'
done

如果您有特殊路径,请将*更改为您的路径+glob:例如:

for i in /home/me/*.exe; do ...

请查看http://mywiki.wooledge.org/glob


1
编辑以解释这种可能性 =) - Gilles Quénot
嘿,Sputnick,你能帮我理解一下你上面写的那段代码吗?我看到你有一个for循环遍历所有内容,但是没有看到你在哪里调用可执行文件来处理图像。你能给我更多的细节和解释吗?谢谢你的帮助和帖子。在这么短的时间内得到这么多的帮助真是太好了。 - Linux Rules
@user1452373 我认为他是在给出一个通用的例子,展示从shell直接执行for循环会做什么,而不是实际执行。我觉得在执行任何涉及循环的文件操作之前进行测试是一个好习惯。 - Steve Buzonas

0

这将在输出图像的名称前添加类似于filtered_filename0055.bmp的内容。

for i in *; do
    ./filter $i filtered_$i lower upper
done

我猜这会覆盖源文件。 - Gilles Quénot
如果文件名中有空格怎么办?那么命令将解析为 ./filter file withspace filtered_file withspace lower upper。在使用时,你应该加上引号 "$i" - Tim Pote
1
@TimPote 根据问题信息,我尽量让它变得简单易懂,但是加上引号会更好,还需要检查文件扩展名和目录。 - Eric Fortis
如果由glob模式捕获的文件中包含空格,则传递给./filter的参数数量将会发生变化。 - Steve Buzonas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接