817 Stimmen

Wie man über Dateien in einem Verzeichnis iteriert und den Pfad ändert und einem Dateinamen ein Suffix hinzufügt

Ich muss ein Skript schreiben, das mein Programm mit unterschiedlichen Argumenten startet. Ich starte mein Programm mit:

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

Hier ist der Pseudocode für das, was ich tun möchte:

für jeden Dateinamen in /Data tun
  für int i = 0, i = 3, i++
    ./MyProgram.exe Data/filename.txt Logs/filename_Log{i}.txt
  end für
end für

Wie kann ich das zweite Argument aus dem ersten erstellen, sodass es wie dataABCD_Log1.txt aussieht und mein Programm startet?

1099voto

Gordon Davisson Punkte 105638

Ein paar Anmerkungen zunächst: wenn Sie Data/data1.txt als Argument verwenden, sollte es wirklich /Data/data1.txt (mit einem führenden Schrägstrich) sein? Soll die äußere Schleife nur nach .txt-Dateien suchen oder nach allen Dateien in /Data? Hier ist eine Antwort, unter der Annahme von /Data/data1.txt und nur .txt-Dateien:

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

Notizen:

  • /Data/*.txt erweitert sich zu den Pfaden der Textdateien in /Data (einschließlich des /Data/Teils)
  • $( ... ) führt einen Shell-Befehl aus und fügt dessen Ausgabe an dieser Stelle in die Befehlszeile ein
  • basename somepath .txt gibt den Basisanteil von somepath aus, wobei .txt am Ende entfernt wird (z.B. /Data/file.txt -> file)

Wenn Sie MyProgram mit Data/file.txt anstelle von /Data/file.txt ausführen müssen, verwenden Sie "${filename#/}", um den führenden Schrägstrich zu entfernen. Andererseits, wenn es wirklich Data und nicht /Data ist, das Sie durchsuchen wollen, verwenden Sie einfach for filename in Data/*.txt.

484voto

Cong Ma Punkte 9762

Immer wenn Sie über Dateien durch Globbing iterieren, ist es ratsam, den Sonderfall zu vermeiden, in dem das Globbing nicht übereinstimmt (wodurch die Schleifenvariable auf den (nicht übereinstimmenden) Glob-Musterstring selbst erweitert wird).

Zum Beispiel:

for filename in Data/*.txt; do
    [ -e "$filename" ] || continue
    # ... Rest des Schleifenkörpers
done

Referenz: Bash Pitfalls

108voto

Jonathan Leffler Punkte 694013
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

Die name=${file##*/} Substitution (shell parameter expansion) entfernt den führenden Dateipfad bis zum letzten /.

Die base=${name%.txt} Substitution entfernt das abschließende .txt. Es ist etwas komplizierter, wenn sich die Erweiterungen ändern können.

35voto

James Andino Punkte 22663

Sie können die Ausgabe der find-Option mit null-separaten Ausgaben von [read](https://en.wikipedia.org/wiki/Read(Unix))_ verwenden, um sicher über Verzeichnisstrukturen zu iterieren.

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

Also für Ihren Fall,

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

Zusätzlich,

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

wird die while-Schleife im aktuellen Bereich des Skripts (Prozess) ausgeführt und ermöglicht die Verwendung der Ausgabe von find zum Setzen von Variablen, wenn nötig.

10voto

Führen Sie einen Befehl auf jeder Datei aus:

Machen Sie etwas (echo) mit allen .txt Dateien,

for f in *.txt; do echo ${f}; done;

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X