如何使用Bash迭代目录中的文件?

时间:2013-12-27 06:49:35

标签: bash for-loop filenames

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

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

这是我想要做的伪代码:

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并启动我的程序。

5 个答案:

答案 0 :(得分:586)

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

#!/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输出somepath的基本部分,从末尾删除.txt(例如/Data/file.txt - &gt; file

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

答案 1 :(得分:240)

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

例如:

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

参考:Bash Pitfalls

答案 2 :(得分:67)

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 parameter expansion)会删除前一个/的前导路径名。

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

答案 3 :(得分:3)

您可以将finds null分隔的输出选项与read一起使用,以安全地遍历目录结构。

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

对于您的情况

#!/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

另外

#!/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的输出用于设置变量

答案 4 :(得分:-2)

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

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

或者猛击

#!/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