关于for循环:如何使用Bash迭代目录中的文件?

How to iterate over files in a directory with Bash?

我需要编写一个脚本,用不同的参数启动我的程序,但我是Bash的新手。 我开始我的程序:

./MyProgram.exe Data/data1.txt [Logs/data1_Log.txt]

这是我想要做的伪代码:

1
2
3
4
5
for each filename in /Data do
  for int i = 0, i = 3, i++
    ./MyProgram.exe Data/filename.txt Logs/filename_Log{i}.txt
  end for
end for

所以我真的很困惑如何从第一个创建第二个参数,所以它看起来像dataABCD_Log1.txt并启动我的程序。


首先注意几个注意事项:当你使用Data/data1.txt作为参数时,它应该是/Data/data1.txt(带有前导斜杠)吗?此外,外部循环是否应仅扫描.txt文件或/ Data中的所有文件?这是一个答案,仅假设/Data/data1.txt和.txt文件:

1
2
3
4
5
6
#!/bin/bash
for filename in /Data/*.txt; do
    for ((i=0; i<=3; i++)); do
        ./MyProgram.exe"$filename""Logs/$(basename"$filename" .txt)_Log$i.txt"
    done
done

笔记:

  • /Data/*.txt扩展到/ Data中的文本文件的路径(包括/ Data / part)
  • $( ... )运行shell命令并在命令行中的该点插入其输出
  • basename somepath .txt输出某路径的基本部分,从末尾删除.txt(例如/Data/file.txt - > file)

如果需要使用Data/file.txt而不是/Data/file.txt运行MyProgram,请使用"${filename#/}"删除前导斜杠。另一方面,如果您想扫描Data而不是/Data,只需使用for filename in Data/*.txt


很抱歉对线程进行了解析,但是每当你通过globbing迭代文件时,最好避免使用glob不匹配的极端情况(这会使循环变量扩展为(不匹配)glob模式字符串本身)。

例如:

1
2
3
4
for filename in Data/*.txt; do
    [ -e"$filename" ] || continue
    # ... rest of the loop body
done

参考:Bash陷阱


1
2
3
4
5
6
7
8
9
for file in Data/*.txt
do
    for ((i = 0; i < 3; i++))
    do
        name=${file##*/}
        base=${name%.txt}
        ./MyProgram.exe"$file" Logs/"${base}_Log$i.txt"
    done
done

name=${file##*/}替换(shell参数扩展)将前导路径名删除到最后一个/

base=${name%.txt}替换删除尾随.txt。如果扩展可以变化,这有点棘手。


您可以使用lookup null分隔输出选项和read来安全地迭代目录结构。

1
2
3
4
#!/bin/bash
find . -type f -print0 | while IFS= read -r -d $'\0' file;
  do echo"$file" ;
done

所以对你的情况

1
2
3
4
5
6
#!/bin/bash
find . -maxdepth 1 -type f  -print0 | while IFS= read -r -d $'\0' file; do
  for ((i=0; i<=3; i++)); do
    ./MyProgram.exe"$file" 'Logs/'"`basename"$file"`""$i"'.txt'
  done
done

另外

1
2
3
4
5
6
#!/bin/bash
while IFS= read -r -d $'\0' file; do
  for ((i=0; i<=3; i++)); do
    ./MyProgram.exe"$file" 'Logs/'"`basename"$file"`""$i"'.txt'
  done
done < <(find . -maxdepth 1 -type f  -print0)

将在脚本(进程)的当前范围内运行while循环,并允许find的输出用于设置变量(如果需要)


看起来你正在尝试执行一个Windows文件(.exe)当然你应该使用PowerShell。无论如何,在一个Linux bash shell上,一个简单的单行程就足够了。

1
[/home/$] for filename in /Data/*.txt; do for i in {0..3}; do ./MyProgam.exe  Data/filenameLogs/$filename_log$i.txt; done done

或者在bash中

1
2
3
4
5
6
7
8
#!/bin/bash

for filename in /Data/*.txt;
   do
     for i in {0..3};
       do ./MyProgam.exe Data/filename.txt Logs/$filename_log$i.txt;
     done
 done