J’ai une sortie SQL * Plus écrite dans un fichier texte au format suivant:
3459906| |2|X1|WAS1| Output1 334596| |2|X1|WAS2| Output1 3495792| |1|X1|WAS1| Output1 687954| |1|X1|WAS2| Output1
J’ai besoin d’un script shell pour récupérer les comptes qui étaient au début basés sur le texte après les comptes.
Par exemple, si le texte est comme |2|X1|WAS1|
, alors 3459906
devrait être transmis à une variable x1was12
et si le texte est comme |2|X1|WAS2|
, alors 334596 devrait être transmis à une variable x1was22
.
J’ai essayé d’écrire une boucle for
et if
condition pour transmettre les comptes, mais a échoué:
export filename1='file1.dat' while read -r line ; do if [[ grep -i "*|2|X1|WAS1| Output1*" | wc -l -eq 0 ]] ; then export xwas12=sed -n ${line}p $filename1 | \ sed 's/[^0-9]*//g' | sed 's/..$//' elif [[ grep -i "*|2|X1|WAS2| Output1*" | wc -l -eq 0 ]] ; then export x1was22=sed -n ${line}p $filename1 | \ sed 's/[^0-9]*//g' | sed 's/..$//' elif [[ grep -i "*|1|X1|WAS1| Output1*" | wc -l -eq 0 ]] ; then export x1was11=sed -n ${line}p $filename1 | \ sed 's/[^0-9]*//g' | sed 's/..$//' elif [[ grep -i "*|1|X1|WAS2| Output1*" | wc -l -eq 0 ]] export x1was21=sed -n ${line}p $filename1 | \ sed 's/[^0-9]*//g' | sed 's/..$//' fi done output.txt echo '$x1was22' >> output.txt echo '$x1was11' >> output.txt echo '$x1was21' >> output.txt
Ce que j’essayais de faire était:
sed
à la variable sed
à une autre variable. while IFS='|' read -r count _ nx was _; do # remove spaces from all variables count=${count// /}; n=${n// /}; x=${x// /}; was=${was// /} varname="${x}${was}${n}" printf -v "${varname,,}" %s "$count" done <<'EOF' 3459906| |2|X1|WAS1| Output1 334596| |2|X1|WAS2| Output1 3495792| |1|X1|WAS1| Output1 687954| |1|X1|WAS2| Output1 EOF
Avec le ci-dessus exécuté:
$ echo "$x1was12" 3459906
Bien entendu, la redirection d'un heredoc pourrait également être remplacée par une redirection à partir d'un fichier.
Comment cela marche-t-il? Disons-le:
IFS='|' read -r count _ nx was _
IFS='|' read -r count _ nx was _
est exécuté, il lit une seule ligne, en le séparant par |
s, en mettant la première colonne en count
, en supprimant la seconde en l'associant à _
, en lisant le troisième dans n
, le quasortingème dans x
, le cinquième dans was
et le sixième et tout le contenu suivant dans _
. Cette pratique est discutée en détail dans BashFAQ # 1 . count=${count// /}
est une extension de paramètre qui élague les espaces du count
variables, en remplaçant tous ces espaces par des chaînes vides. Voir aussi BashFAQ # 100 . "${varname,,}"
est un autre paramètre d'extension, celui-ci convertissant le contenu d'une variable en minuscules. (Cela nécessite bash 4.0; dans les versions précédentes, considérez "$(tr '[:upper:]' '[:lower:]' <<<"$varname")
comme alternative moins efficace). printf -v "$varname" %s "value"
est un mécanisme permettant d' affecter indirectement la variable nommée dans la variable varname
. Sinon pour les noms de variables, le tout pourrait être fait avec deux commandes:
cut -d '|' -f1 file1.dat | tr -d ' ' > output.txt
Les noms de variables le rendent plus intéressant. Deux méthodes bash
suivent, plus une méthode POSIX …
Le code bash
suivant devrait faire ce que le code exemple de l’OP était censé faire:
declare $(while IFS='|' read abcdef ; do echo $a 1>&2 ; echo x1${e,,}$c=${a/ /} done < file1.dat 2> output.txt )
Remarques:
bash
est nécessaire pour ${e,,}
(transforme ” WAS ” en ” was “) et $a/ /}
(supprime un espace principal qui pourrait être dans $a
) et declare
. La boucle while parsing file1.dat
et file1.dat
un ensemble d’affectations de variables. Sans declare
ce code:
while IFS='|' read abcdef ; do echo x1${e,,}$c=${a/ /} ; done < file1.dat
Les sorties:
x1was12=3459906 x1was22=334596 x1was11=3495792 x1was21=687954
La boucle while sort vers deux stream distincts: stdout (pour le declare
) et stderr (utilisant les redirections 1>&2
et 2>
pour output.txt
).
Utiliser des tableaux associatifs bash
:
declare -A x1was="( $(while IFS='|' read abcdef ; do echo $a 1>&2 ; echo [${e/WAS/}$c]=${a/ /} done < file1.dat 2> output.txt ) )"
Dans ce cas, les noms de variable nécessitent des crochets:
echo ${x1was[21]} 687954
Code shell POSIX (testé avec dash
):
eval $(while IFS='|' read abcdef ; do echo $a 1>&2; echo x1$(echo $e | tr '[AZ]' '[az]')$c=$(echo $a) done < file1.dat 2> output.txt )
eval
ne doit pas être utilisé en cas de doute sur ce que file1.dat
. Le code ci-dessus suppose que les données de file1.dat
sont uniformément fiables.