web-dev-qa-db-fra.com

Grep sur plusieurs fichiers redirigeant vers un nom de fichier différent à chaque fois

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?

11
jtyun

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:

  • les quatre premiers caractères du nom de fichier - l'année
  • la lettre Q
  • le 9ème caractère du nom de fichier - le quart
12
Jeff Schaller

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"
5

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)
2
bu5hman

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'
  1. ls répertorie simplement les fichiers que vous souhaitez traiter
  2. xargs traiter chacun de ces fichiers, un par un (- n1)
  3. a bash Shell est lancé pour pouvoir traiter les chaînes (cf point 5)
  4. Définit le nom de fichier sur variable $ f
  5. $ {f // [^ 0-9Q] /} supprime tous les caractères que vous ne voulez pas dans les noms de fichiers .txt (c'est donc spécifique à votre exemple)

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)

0
Jacques