Как перебирать файлы в каталоге с помощью Bash?

мне нужно написать сценарий, который запускает мою программу с разными аргументами, но я новичок в 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 if
end for

поэтому я действительно озадачен тем, как создать второй аргумент из первого, поэтому он выглядит как dataABCD_Log1.txt и запустите мою программу. Помощь очень ценится.

P.S. Я знаю, что есть аналогичные вопросы, но я нашел ничего о создании моего имени файла журнала.

4 ответов


пара заметок сначала: когда вы используете Data/data1.txt в качестве аргумента, если это действительно должно быть /Data/data1.txt (с ведущим слешем)? Кроме того, должен внешний цикл сканировать только для.txt файлы или все файлы в /Data? Вот ответ, предполагающий /Data/data1.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 (в том числе the / Data / part)
  • $( ... ) запускает команду оболочки и вставляет ее вывод в этот момент в командной строке
  • basename somepath .txt выводит базовую часть somepath, С.txt удален с конца (например,/Data/file.txt ->file)

Если вам нужно запустить MyProgram с Data/file.txt вместо /Data/file.txt используйте "${filename#/}" убрать Слэш. С другой стороны, если это действительно Data не /Data вы хотите сканировать, просто используйте for filename in Data/*.txt.


к сожалению для некромантии нить, но всякий раз, когда вы перебирать файлы по имени, это хорошая практика, чтобы избежать угловой случае, когда шар не совпадает (что делает переменная цикла и раскройте в (не-соответствия) Глоб шаблон строку).

например:

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

ссылки: Bash Подводные Камни


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##*/} замена (расширение параметров оболочки) удаляет ведущий путь до последнего /.

на base=${name%.txt} замена удаляет замыкающие .txt. Это немного сложнее, если расширения могут различаться.


то, что я использую, чтобы избежать дополнительных строк или проверок:

#!/bin/bash
for filename in $(find /Data/*.txt 2> /dev/null); do
    for ((i=0; i<=3; i++)); do
        ./MyProgram.exe "$filename" "Logs/$(basename "$filename" .txt)_Log$i.txt"
    done
done

идея состоит в том, чтобы запустить поиск в подрешетке и отправить ошибки в /dev/null, чтобы вы никогда не перебирали ошибку об отсутствующих файлах.