Ich habe eine Datei mit Benutzernamen und Passwörtern im JSON-Format, die ich zur Verarbeitung konvertieren möchte.
Ich habe sed
zur Verarbeitung unterschiedliche Befehle verwendet, möchte aber wissen, wie ich in Zukunft alle drei Befehle zu einem zusammenfassen kann.
Originalformat
{ "user.name1" : "hashed_password",
"user.name2" : "hashed_password" }
Gewünschte Ausgabe
user.name:hashed_password
Dies sind die Befehle, die ich ausgeführt habe. Allerdings konnte ich sie weder per Pipe noch durch einfaches Verketten miteinander verketten, wodurch ich eine Fehlermeldung erhielt sed: -e expression #1, char 8: unknown option to 's'
.
Anstößiger Befehl …
sed -i 's/\"//g/s/\,/\n/g/\s//g' input_file
sed: -e expression #1, char 8: unknown option to `s'
Wie können die folgenden Befehle zu einem einzigen Befehl zusammengefügt werden?
Befehle Doppelte Anführungszeichen entfernen
sed -i 's/\"//g' input_file
Komma durch neue Zeile ersetzen
sed -i 's/\,/\n/g' input_file
Leerzeichen entfernen
sed -i 's/\s//g input_file
Antwort1
Um mehrere sed
Befehle in einem einzigen "Skript", können Sie mehrere -e
Flags verwenden (was portierbar ist):
sed -i -e 's/\"//g' -e 's/\,/\n/g' -e 's/\s//g' input_file
Oder das Semikolon-Trennzeichen (das nicht bei allen Implementierungen verfügbar ist):
sed -i 's/\"//g;s/\,/\n/g;s/\s//g' input_file
Sie müssen auch eine Handhabung für die Klammern hinzufügen - {}
...
Um JSON richtig zu analysieren und zu verarbeiten, sollten Sie jedoch nicht wirklich verwenden sed
... versuchen Sie es vielleicht mitjq
!
jq -r 'keys[] as $k | "\($k):\(.[$k])"' input_file
Ausgabe:
user.name1:hashed_password
user.name2:hashed_password
keys[] as $k
durchläuft jeden Schlüssel und speichert seinen Wert in$k
- dh:
user.name1
,user.name2
- dh:
"\($k):\(.[$k])"
wird eine Zeichenfolge bilden, ersetzen in$k
und.[$k]
- Mit
-r
werden die Anführungszeichen aus den Ausgabezeichenfolgen entfernt (rohModus)
Die Verwendung sed
zur Verarbeitung von JSON bringt alle möglichen Probleme mit sich. Wie würden Sie beispielsweise mit der folgenden (vollständig gültigen JSON-)Eingabe umgehen?
{
"user.name1" :
"hashed_password",
"user.name2" :
"hashed_password"
}
Antwort2
Wenn Sie mit standardisierten Eingaben wie JSON arbeiten, ist es im Allgemeinen besser, einen richtigen Parser anstelle von regulären Ausdrücken zu verwenden. So konvertieren Sie beispielsweise alle Escape-Sequenzen korrekt (obwohl das bei Ihren speziellen Eingabedaten möglicherweise nicht möglich ist!).
Leider gibt es in Coreutils keine großartigen Tools für die Verarbeitung von JSON.Attie hat bereitgestellt jq
als gute Option, wenn Sie Pakete frei installieren können.
Wenn Sie keine zusätzlichen Pakete installieren können, ist das in Python nicht besonders schwierig. Nehmen Sie zum Beispiel dieses Skript:
import json,sys
for (k, v) in json.load(sys.stdin):
print(k + ":" + v)
Was sich in einer Zeile zusammenfassen lässt:
cat inputdata | python -c 'import json,sys;print("\n".join((k + ":" + v) for (k, v) in json.load(sys.stdin).items()))'
Antwort3
Für die einfache Zeichenlöschung, die Sie mit diesen sed
Befehlen durchführen, würde ich Ihnen stattdessen empfehlen, zu verwenden tr
, dessen einziger Zweck darin besteht, einzelne Zeichen, einschließlich Zeilenumbrüche, zu löschen, zu komprimieren oder zu ersetzen ( sed
basiert auf regulären Ausdrücken, die normalerweise Zeilenumbrüche als Puffertrennzeichen verwenden, daher ist die Verwendung von sed zum Ändern von Zeilenumbrüchen schwierig). Ich denke, dieser tr
Befehl macht alles, was Sie suchen:
cat json_filename | tr -d "{}\" \012\011\015" | tr "," "\012"
Der erste tr
Befehl löscht alle geschweiften Klammern, Anführungszeichen, Leerzeichen, Wagenrücklaufzeichen (Oktal 012, ASCII 10), Tabulatorzeichen (Oktal 011, ASCII 9) und Zeilenvorschubzeichen (Oktal 015, ASCII 13). Der zweite tr
Befehl ersetzt alle Kommas durch Wagenrücklaufzeichen. Solange die Variablennamen und -werte Ihrer JSON-Datei keine Kommas enthalten, können Sie mit diesen Befehlen auf einen dedizierten JSON-Parser verzichten.
Wenn Sie jedoch einen Satz von sed
Befehlen haben, die jeweils unabhängig voneinander funktionieren, können Sie diese am einfachsten mit der sed
Option „-f“ kombinieren, um die einzelnen Befehle aus einer Datei zu lesen. Sie fügen einfach die Zeichenfolgen s/.../.../g in eine Datei ein, jede Zeichenfolge in einer eigenen Zeile, und geben diesen Dateinamen dann nach der Option „-f“ an. Wenn beispielsweise die drei von sed
Ihnen aufgelisteten Befehle zufriedenstellend sind, können Sie sie in eine Datei mit dem Namen „json.convert.sed“ einfügen, die einfach Folgendes enthält:
s/\"//g
s/\,/\n/g
s/\s//g
Anschließend rufen Sie sed
die Datei mit folgendem Befehl auf:
sed -f json.convert.sed
Allerdings sed
funktionieren diese Befehle bei mir nicht, um das zu erreichen, was Sie wollen, und ich bin mir nicht sicher, ob Sie jemals sed
Zeilenumbruchzeichen ändern können. Das liegt daran, dass sed
auf dem alten Zeileneditor „ed“ basiert, der zum Bearbeiten einzelner Zeilen auf einmal konzipiert ist (eine „skriptfähige“ Version davon), sodass jede Eingabezeile mit Zeilenumbrüchen als Trennzeichen „analysiert“ wird, dann wird die Zeile (ohne den Zeilenumbruch) an die Bearbeitungs-Engine übergeben, die Bearbeitungsbefehle werden angewendet, dann wird die bearbeitete Zeile mit einem Zeilenumbruch ausgegeben. Dann wiederholt sich die Schleife. Ich konnte sed
Zeilenumbrüche bisher nur ändern, indem ich zuerst die Zeilenumbrüche mit in ein anderes Zeichen (das sonst nicht in der Eingabe erscheint) geändert habe tr
. Es macht keinen Sinn, tr
diese Methode zu verwenden, wenn Sie nur Zeilenumbrüche löschen möchten, da tr
dies für Sie erledigt. Wenn Sie jedoch beispielsweise Zeilenumbrüche in Semikolons mit einem abschließenden Leerzeichen umwandeln möchten, wäre eine Möglichkeit, dies zu tun:
cat input_file | tr "\012" "%" | sed "s/%/; /g"
(Zeilenumbrüche werden von in % umgewandelt tr
, anschließend sed
werden alle %-Zeichen in "; "-Zeichenpaare umgewandelt.)
Antwort4
Man könnte es so kombinieren:
sed -i 's/\"//g;s/\,/\n/g;s/\s//g' input_file
Sie haben vergessen, die Entfernung von hinzuzufügen {}
. Sie möchten also wahrscheinlich:
sed -i 's/\"//g;s/\,/\n/g;s/\s//g;s/{//g;s/}//g' input_file