J'ai un répertoire plein de fichiers .tsv et je veux exécuter une commande grep sur chacun d'eux pour extraire un certain groupe de lignes de texte, puis l'enregistrer dans un fichier texte associé avec un nom de fichier similaire. Ainsi, par exemple, si je ne saluais qu'un seul des fichiers, ma commande grep ressemble à ceci:
grep -h 8-K 2008-QTR1.tsv > 2008Q1.txt
Mais j'ai une liste de fichiers tsv qui ressemblent à:
2008-QTR1.tsv
2008-QTR2.tsv
2008-QTR3.tsv
2008-QTR4.tsv
2009-QTR1.tsv
2009-QTR2.tsv
2009-QTR3.tsv
...
Et après avoir salué, ils doivent être stockés sous:
2008Q1.txt
2008Q2.txt
2008Q3.txt
2008Q4.txt
2009Q1.txt
2009Q2.txt
2009Q3.txt
Des pensées?
Dans ksh93/bash/zsh, avec une simple boucle for
et une expansion des paramètres:
for f in *-QTR*.tsv
do
grep 8-K < "$f" > "${f:0:4}"Q"${f:8:1}".txt
done
Cela exécute le grep
sur un fichier à la fois (où cette liste de fichiers est générée à partir d'un modèle générique qui nécessite que "-QTR" existe dans le nom de fichier ainsi qu'un ".tsv" se terminant par le nom de fichier ), redirigeant la sortie vers un nom de fichier soigneusement construit basé sur:
Q
La variante obligatoire POSIX sh
:
#! /bin/sh -
ret=0
for file in [[:digit:]][[:digit:]][[:digit:]][[:digit:]]-QTR[1234].tsv; do
base=${file%.tsv}
grep 8-K < "$file" > "${base%%-*}Q${base##*-QTR}".txt || ret=$?
done
exit "$ret"
Une autre option
for f in 200{8..9}-QTR{1..4}.tsv; do
grep "pattern" $f > $(sed "s/[-RTtsv]*//g" <<< $f)txt;
done
Procédure pas à pas: configurez une extension qui crée une liste de vos noms de fichiers
200{8..9}-QTR{1..4}.tsv
s'étend à
2008-QTR1.tsv 2008-QTR2.tsv 2008-QTR3.tsv 2008-QTR4.tsv 2009-QTR1.tsv 2009-QTR2.tsv 2009-QTR3.tsv 2009-QTR4.tsv
et de faire chaque année et trimestre à ce jour serait
20{08..19}-QTR{1..4}.tsv
Itérer sur la liste for..do..done
, extrayez le motif que vous recherchez à partir du fichier
grep "pattern" $f
et redirigez vers le nouveau nom de fichier formé en supprimant les caractères indésirables avec sed
et en ajoutant le suffixe txt
$(sed "s/[-RTtsv]*//g" <<< $f)txt
ou
$(sed "s/[-RT]*//g" <<< ${f%%.*}.txt)
Si vous souhaitez éviter une boucle explicite, il existe la solution suivante. Quelqu'un pourra peut-être l'améliorer. Cela ressemble à ceci.
ls -1 *.tsv | xargs -n1 -I'{}' bash -c 'f="{}";grep 8-K $f > ${f//[^0-9Q]/}.txt'
Avantages: - Simple one liner
Inconvénients: - Un processus bash est démarré pour chaque fichier traité
Peut-être existe-t-il une solution similaire sans utiliser bash, mais je n'en connais pas (par exemple, eval ne devrait pas fonctionner dans ce contexte)