Трябва да напиша скрипт, който да стартира програмата ми с различни аргументи, но съм новак в 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 и да стартирам програмата си.
Първо няколко забележки: когато използвате 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/)$( ... )
изпълнява команда на шел и вмъква нейния изход в тази точка на командния ред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 Pitfalls
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=${име%.txt}
премахва крайния .txt
. Това е малко по-трудно, ако разширенията могат да варират.