Je dois écrire un script qui démarre mon programme avec des arguments différents, mais je ne connais pas encore Bash. Je commence mon programme avec:
./MyProgram.exe Data/data1.txt [Logs/data1_Log.txt]
.
Voici le pseudocode pour ce que je veux faire:
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
Je suis donc vraiment perplexe de savoir comment créer un deuxième argument à partir du premier. Cela ressemble donc à dataABCD_Log1.txt et au démarrage de mon programme.
Quelques notes tout d’abord: lorsque vous utilisez Data/data1.txt
comme argument, faut-il que ce soit vraiment /Data/data1.txt
(avec une barre oblique)? En outre, la boucle externe doit-elle uniquement rechercher les fichiers .txt ou tous les fichiers de/Data? Voici une réponse, en supposant que /Data/data1.txt
et les fichiers .txt uniquement:
#!/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
Remarques:
/Data/*.txt
étend les chemins des fichiers texte dans/Data (y compris le/Data/part)$( ... )
exécute une commande Shell et insère sa sortie à cet endroit de la ligne de commandebasename somepath .txt
génère la partie de base de somepath, le fichier .txt étant supprimé de la fin (par exemple, /Data/file.txt
-> file
)Si vous avez besoin d'exécuter MyProgram avec Data/file.txt
au lieu de /Data/file.txt
, utilisez "${filename#/}"
pour supprimer la barre oblique. D'un autre côté, s'il s'agit vraiment de Data
et non de /Data
que vous souhaitez analyser, utilisez simplement for filename in Data/*.txt
.
Désolé de nécromancer le thread, mais chaque fois que vous effectuez une itération sur des fichiers en effectuant un regroupement, il est recommandé d'éviter le coin où le regroupement ne correspond pas (ce qui permet à la variable de boucle de se développer elle-même (sans correspondance).
Par exemple:
for filename in Data/*.txt; do
[ -e "$filename" ] || continue
# ... rest of the loop body
done
Référence: pièges 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
La substitution name=${file##*/}
( extension du paramètre Shell ) supprime le chemin précédent jusqu'au dernier /
.
La substitution base=${name%.txt}
supprime le .txt
final. C'est un peu plus délicat si les extensions peuvent varier.
Vous pouvez utiliser l'option de sortie séparée de la recherche null avec read pour parcourir en toute sécurité les structures de répertoires.
#!/bin/bash
find . -type f -print0 | while IFS= read -r -d $'\0' file;
do echo "$file" ;
done
Donc pour votre cas
#!/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
aditionellement
#!/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)
exécutera la boucle while dans la portée actuelle du script (processus) et autorisera l'utilisation de la sortie de find dans la définition de variables, si nécessaire