Inhaltsverzeichnis
Dateiname mit Leerzeichen verarbeiten
Ein Problem bei der Verarbeitung von Dateien sind Leerzeichen in Verzeichnis- oder Dateinamen. Hier hilft das Speichern der Command-Ausgaben wie z.B. von ls oder find in einem Array.
Ausgabe von ls:
host:/tmp/test$ ls -d1 * /tmp/test/Leerzeichen im Dateinamen sind doof.txt /tmp/test/Links.txt /tmp/test/Liste mit irgenwas.txt /tmp/test/Liste mit was anderem.txt /tmp/test/Rezepte.txt
Der Versuch alles in Variablen bzw. ein Array zu speichern ergibt kein brauchbares Ergebnis:
host:/tmp/test$ X=($(ls -d1 *.txt)) host:/tmp/test$ for I in ${X[*]};do echo $I;done /tmp/test/Leerzeichen im Dateinamen sind doof.txt /tmp/test/Links.txt /tmp/test/Liste mit irgenwas.txt /tmp/test/Liste mit was anderem.txt /tmp/test/Rezepte.txt
Wird $IFS geändert IFS=$’\n‘ belegt jede Datei einen Array-Index:
IFS_BAK=$IFS IFS=$'\n' X=($(ls -d1 *.txt)) for I in ${X[*]} do echo $I done
/tmp/test/Leerzeichen im Dateinamen sind doof.txt /tmp/test/Links.txt /tmp/test/Liste mit irgenwas.txt /tmp/test/Liste mit was anderem.txt /tmp/test/Rezepte.txt
Text-Datei zeilenweise verarbeiten
Um eine Datei zeilenweise zu bearbeiten kann sie durch die Änderung der Variable $IFS in ein Array eingelesen und dann bearbeitet bzw. ausgewertet werden. Dabei steht im folgenden Beispiel der Array-Index 0 für die erste Zeile der Datei.
Ein einfaches Beispiel:
host:~ # cat /etc/SuSE-release SUSE Linux Enterprise Server 11 (x86_64) VERSION = 11 PATCHLEVEL = 2
Die Datei in ein Array einlesen:
host:~ # IFS_BAK=$IFS host:~ # IFS="$" host:~ # X=($(cat -E /etc/SuSE-release)) host:~ # IFS=$IFS_BAK
so gehts auch:
i=0; while IFS= read -r X[i++]; do :; done < /etc/SuSE-release
seit bash 4:
readarray -t X < /etc/SuSE-release
Ergibt:
host:~ # echo ${X[*]} SUSE Linux Enterprise Server 11 (x86_64) VERSION = 11 PATCHLEVEL = 2 host:~ # host:~ # echo ${X[0]} SUSE Linux Enterprise Server 11 (x86_64) host:~ # echo ${X[1]} VERSION = 11 host:~ # echo ${X[2]} PATCHLEVEL = 2
Thema Performance:
Eine Testdatei mit 100000 Zeilen:
host:~/tmp$ seq 100000 199999 >> zeilen.txt
schnell
markus@as-deb-01:~/tmp$ time (readarray -t X < zeilen2.txt) real 0m0.037s user 0m0.024s sys 0m0.012s
langsam
markus@as-deb-01:~/tmp$ time (IFS="$";X=($(cat -E zeilen2.txt))) real 0m0.171s user 0m0.156s sys 0m0.016s
sehr langsam
markus@as-deb-01:~/tmp$ time (i=0; while IFS= read -r A[i++]; do :; done < zeilen2.txt) real 0m6.720s user 0m3.948s sys 0m2.760s
SNMP-Ausgabe verarbeiten
Ein Beispiel um mehrzeiligen snmpget-Output zu verarbeiten.
server:~ # snmpget -v 2c 172.16.42.11 -c comxyz -O s SNMPv2-MIB::sysName.0 SNMPv2-MIB::sysDescr.0 SNMPv2-MIB::sysUpTime.0 sysName.0 = STRING: switch-01.mg-it.net sysDescr.0 = STRING: Cisco IOS Software, C3750E Software (C3750E-UNIVERSALK9-M), Version 12.2(55)SE3, RELEASE SOFTWARE (fc1) Technical Support: http://www.cisco.com/techsupport Copyright (c) 1986-2011 by Cisco Systems, Inc. Compiled Thu 05-May-11 15:40 by prod_rel_team sysUpTimeInstance = Timeticks: (3828601894) 443 days, 3:00:18.94
Das folgende Script schreibt die Ausgabe in ein Array:
IFS_BAK=$IFS IFS=$'\n' SNMPOUT=($(snmpget -v 2c 172.16.42.11 -c comxyz -O vq \ SNMPv2-MIB::sysName.0 \ SNMPv2-MIB::sysDescr.0 \ SNMPv2-MIB::sysUpTime.0)) for I in ${SNMPOUT[@]} do echo "$I" done IFS=$IFS_BAK
Ausgabe des Array:
switch-01.mg-it.net Cisco IOS Software, C3750E Software (C3750E-UNIVERSALK9-M), Version 12.2(55)SE3, RELEASE SOFTWARE (fc1) Technical Support: http://www.cisco.com/techsupport Copyright (c) 1986-2011 by Cisco Systems, Inc. Compiled Thu 05-May-11 15:40 by prod_rel_team 443:3:54:41.55
Die weiter Verarbeitung könnte so aussehen:
HOSTNAME=${SNMPOUT[0]} IFS="," DESCR=(${SNMPOUT[1]}) VERSION="${DESCR[1]} ${DESCR[2]}" IFS=":" TIMESTAMP=(${SNMPOUT[5]}) UPTIME="${TIMESTAMP[0]} days, ${TIMESTAMP[1]}:${TIMESTAMP[2]}:${TIMESTAMP[3]}" echo $HOSTNAME echo $VERSION echo $UPTIME
switch-01.mg-it.net C3750E Software (C3750E-UNIVERSALK9-M) Version 12.2(55)SE3 443 days 3:54:41.55