IFS und Bash-Array – Texte und Commandoutput verarbeiten

letzte Änderung: 3. Jan 2015, 22:28 Veröffentlicht: 6. Feb 2008, 23:19

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