Ich habe ein Problem mit der Ausgabe eines Programms. Ich muss einen Befehl in Bash starten, dessen Ausgabe (einen String) nehmen und ihn aufteilen, um an bestimmten Stellen neue Zeilen hinzuzufügen. Der String sieht folgendermaßen aus:
battery.charge: 90 battery.charge.low: 30 battery.runtime: 3690 battery.voltage: 230.0 device.mfr: MGE UPS SYSTEMS device.model: Pulsar Evolution 500
im Grunde ist es einxxx.yy.zz:Wert, aber der Wert kann Leerzeichen enthalten. Hier ist die Ausgabe, die ich erhalten möchte
battery.charge: 90
battery.charge.low: 30
battery.runtime: 3690
battery.voltage: 230.0
device.mfr: MGE UPS SYSTEMS
device.model: Pulsar Evolution 500
Ich habe die Idee, nach dem ersten Punkt zu suchen und dann von dieser Position aus nach einem Leerzeichen zu suchen, um dort eine neue Zeile einzufügen, aber ich bin nicht sicher, wie ich das in Bash erreichen kann.
Antwort1
Reine Bash-Lösung, keine externen Tools zur Verarbeitung der Zeichenfolgen verwendet, nur Parametererweiterung:
#! /bin/bash
str='battery.charge: 90 battery.charge.low: 30 battery.runtime: 3690 battery.voltage: 230.0 device.mfr: MGE UPS SYSTEMS device.model: Pulsar Evolution 500'
IFS=: read -a fields <<< "$str"
for (( i=0 ; i < ${#fields[@]} ; i++ )) ; do
f=${fields[i]}
notfirst=$(( i>0 ))
last=$(( i+1 == ${#fields[@]} ))
(( notfirst )) && echo -n ${f% *}
start=('' $'\n' ' ')
colon=('' ': ')
echo -n "${start[notfirst + last]}${f##* }${colon[!last]}"
done
echo
Erklärung: $notfirst
und $last
sind Boolesche Werte. Der Teil vor dem letzten Leerzeichen ${f% *}
wird für das erste Feld nicht gedruckt, da es so etwas nicht gibt. $start
und $colon
enthalten verschiedene Zeichenfolgen, die die Felder trennen: Beim ersten Element notfirst + last
ist 0, also wird nichts vorangestellt, für den Rest der Zeilen $notfirst
ist 1, also wird eine neue Zeile gedruckt, und für die letzte Zeile ergibt die Addition 2, also wird ein Leerzeichen gedruckt. Dann wird der Teil nach dem letzten Leerzeichen gedruckt ${f##* }
. Doppelpunkt wird für alle Zeilen außer der letzten gedruckt.
Antwort2
Mit GNU sed können Sie jeden zusammenhängenden String (also ohne Leerzeichen), der mit endet, abgleichen :
und dann vor allen außer dem ersten einen Zeilenumbruch einfügen:
sed 's/[^[:space:]]\+:/\n&/g2'
Wenn Ihre Version von sed die Erweiterung nicht unterstützt gn
, können Sie einen einfachen g
Modifikator verwenden
sed 's/[^[:space:]]\{1,\}:/\
&/g'
das funktioniert genauso, außer dass vor dem ersten Schlüssel eine zusätzliche neue Zeile gedruckt wird. Sie können perl -pe 's/\S+:/\n$&/g'
mit derselben Einschränkung verwenden (es gibt möglicherweise ein Perl-Äquivalent zu GNU sed, g2
aber ich kenne es nicht).
Antwort3
Eine perl
Lösung:
$ perl -pe 's{\S+:}{$seen++ ? "\n$&" : "$&"}ge' file
battery.charge: 90
battery.charge.low: 30
battery.runtime: 3690
battery.voltage: 230.0
device.mfr: MGE UPS SYSTEMS
device.model: Pulsar Evolution 500
Erläuterung
\S+:
stimmt mit dem Zeichenfolgenende überein:
.- Bei allen übereinstimmenden Zeichenfolgen fügen wir vor ihnen,
("\n$&")
außer vor der ersten , eine neue Zeile ein($seen++)
.
Antwort4
Hier ist ein naiver Ansatz, der funktionieren sollte, vorausgesetzt, es ist Ihnen egal, dass Tabulatoren und Zeilenumbrüche in der Eingabe (falls vorhanden) in einfache Leerzeichen umgewandelt werden.
Die Idee ist einfach: Teilen Sie die Eingabe bei Leerzeichen auf und drucken Sie jedes Token aus, außer dass Sie Token, die mit enden, :
ein neues Zeilenende voranstellen (und vor den anderen wieder ein Leerzeichen hinzufügen). Die $count
Variable und das zugehörige if
sind nur nützlich, um eine anfängliche leere Zeile zu verhindern. Könnte entfernt werden, wenn das kein Problem ist. (Das Skript geht davon aus, dass sich die Eingabe in einer Datei namens intput
im aktuellen Verzeichnis befindet.)
#! /bin/bash
count=0
for i in $(<input) ; do
fmt=
if [[ $i =~ :$ ]] ; then
if [[ $count -gt 0 ]] ; then
fmt="\n%s"
else
fmt="%s"
fi
((count++))
else
fmt=" %s"
fi
printf "$fmt" "$i"
done
echo
echo "Num items: $count"
Ich hoffe jedoch, dass jemand eine schönere Alternative findet.
$ cat input
battery.charge: 90 battery.charge.low: 30 battery.runtime: 3690 battery.voltage: 230.0 device.mfr: MGE UPS SYSTEMS device.model: Pulsar Evolution 500
$ ./t.sh
battery.charge: 90
battery.charge.low: 30
battery.runtime: 3690
battery.voltage: 230.0
device.mfr: MGE UPS SYSTEMS
device.model: Pulsar Evolution 500
Num items: 6