it-swarm.com.de

So durchlaufen Sie Dateien im Verzeichnis und ändern den Pfad und fügen dem Dateinamen ein Suffix hinzu

Ich muss ein Skript schreiben, das mein Programm mit verschiedenen Argumenten startet, aber ich bin neu in Bash. 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:

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

Ich bin wirklich verwirrt, wie ich das zweite Argument aus dem ersten erstellen kann. Es sieht also aus wie dataABCD_Log1.txt und startet mein Programm.

487
Dobrobobr

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

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

Anmerkungen:

  • /Data/*.txt erweitert die Pfade der Textdateien in/Data (einschließlich the/Data/part)
  • $( ... ) führt einen Shell-Befehl aus und fügt seine Ausgabe an dieser Stelle in die Befehlszeile ein
  • basename somepath .txt gibt den Basisteil von somepath aus, wobei TXT vom Ende entfernt wird (z. B. /Data/file.txt -> file).

Wenn Sie MyProgram mit Data/file.txt anstelle von /Data/file.txt ausführen mussten, entfernen Sie den führenden Schrägstrich mit "${filename#/}". Wenn es sich jedoch wirklich um Data und nicht um /Data handelt, den Sie scannen möchten, verwenden Sie einfach for filename in Data/*.txt.

640
Gordon Davisson

Es tut uns leid, dass Sie den Thread nicht synchronisiert haben, aber wenn Sie durch Globbing über Dateien iterieren, ist es ratsam, den Eckfall zu vermeiden, in dem der Glob nicht übereinstimmt (wodurch die Schleifenvariable auf den (nicht übereinstimmenden) Glob-Muster-String selbst erweitert wird).

Zum Beispiel:

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

Hinweis: Bash Fallstricke

274
Cong Ma
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 Ersetzung name=${file##*/} ( Shell-Parametererweiterung ) entfernt den führenden Pfadnamen bis zum letzten /.

Die Ersetzung base=${name%.txt} entfernt den nachfolgenden .txt. Es ist etwas kniffliger, wenn die Erweiterungen variieren können.

68

Sie können die Ausgabeoption finds null mit read verwenden, um Verzeichnisstrukturen sicher zu durchlaufen.

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

Also für deinen 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)

führt die while-Schleife im aktuellen Bereich des Skripts (Prozesses) aus und ermöglicht, dass die Ausgabe von find bei Bedarf zum Festlegen von Variablen verwendet wird

5
Arcabard