Mehrere sed-Befehle in Bash

Mehrere sed-Befehle in Bash

Ich habe eine Datei mit Benutzernamen und Passwörtern im JSON-Format, die ich zur Verarbeitung konvertieren möchte.

Ich habe sedzur 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 sedBefehle in einem einzigen "Skript", können Sie mehrere -eFlags 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 $kdurchläuft jeden Schlüssel und speichert seinen Wert in$k
    • dh: user.name1,user.name2
  • "\($k):\(.[$k])"wird eine Zeichenfolge bilden, ersetzen in $kund.[$k]
  • Mit -rwerden die Anführungszeichen aus den Ausgabezeichenfolgen entfernt (rohModus)

Die Verwendung sedzur 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 jqals 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 sedBefehlen 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 ( sedbasiert 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 trBefehl macht alles, was Sie suchen:

cat json_filename | tr -d "{}\" \012\011\015" | tr "," "\012"

Der erste trBefehl 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 trBefehl 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 sedBefehlen haben, die jeweils unabhängig voneinander funktionieren, können Sie diese am einfachsten mit der sedOption „-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 sedIhnen 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 seddie Datei mit folgendem Befehl auf:

sed -f json.convert.sed

Allerdings sedfunktionieren diese Befehle bei mir nicht, um das zu erreichen, was Sie wollen, und ich bin mir nicht sicher, ob Sie jemals sedZeilenumbruchzeichen ändern können. Das liegt daran, dass sedauf 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 sedZeilenumbrü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, trdiese Methode zu verwenden, wenn Sie nur Zeilenumbrüche löschen möchten, da trdies 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 sedwerden 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

verwandte Informationen