Ersetzen Sie eine lange Zeichenfolge durch den Befehl sed: Argumentliste zu langer Fehler

7

Ich versuche diesen Befehl auszuführen

sed -i -e "s/BASE_64/$BASE_64/" FILE_NAME

Dabei $BASE_64handelt es sich um eine Basis-64-Darstellung eines Dateiinhalts.

sed gibt mir einen Fehler, da die Zeichenfolge zu lang ist.

Argumentliste zu lang

Wie kann dieser Fehler vermieden werden?

Lorenzo B.
quelle

Antworten:

5

Speichern Sie zunächst die base64-codierten Daten in einer Datei mit dem Namen z base64.txt.

Zum Beispiel:

base64 < originalfile > base64.txt

Dann:

printf '%s\n' '/BASE64/r base64.txt' 1 '/BASE64/d' w | ed FILENAME

Dies wird verwendet ed, um FILENAMEnach einer Zeile zu suchen , die die Zeichenfolge enthält BASE64, den Inhalt base64.txtnach dieser Zeile einzufügen , zur ersten Zeile zurückzukehren, dann erneut nach der Zeile mit der Zeichenfolge zu suchen BASE64und sie zu löschen. Der wBefehl in edspeichert die geänderte Datei.

cas
quelle
Was ist, wenn dies BASE64nur ein Teil der Leitung ist und Sie nicht die gesamte Leitung ersetzen möchten?
Eric Renouf
base64-Text ist in der Regel mehrzeilig ( viele Zeilen), daher ist das Einfügen in die Mitte einer Zeile sinnlos. Ich würde die /BASE64/r base64.txtEinfügung wie oben machen und dann s/BASE64//eher als /BASE64/d.
Cas
Dies kann sein, dass ein kurzes Beispiel, bei dem die verschlüsselten Daten in der nächsten Zeile beschädigt würden, darin besteht, dass Sie eine kurze Base64-codierte Zeichenfolge hätten, wenn Sie den Autorisierungsheader für eine HTTP-Anforderung mithilfe der Standardauthentifizierung ausfüllen würden an Ort und Stelle ersetzt werden, angesichts des vorliegenden Problems, das ist wahrscheinlich nicht die Situation in diesem Fall
Eric Renouf
In einem solchen Fall wäre es a) äußerst unwahrscheinlich, dass ein "Argumentliste zu langer Fehler" wie der gemeldete OP verursacht wird, und b) ich würde eine Methode verwenden, die für die jeweilige Aufgabe besser geeignet ist ... eine einfache s/BASE_64/$BASE_64_TEXT/mit sed oder ed oder perl oder was auch immer würde wahrscheinlich ausreichen.
Cas
5

Sie können dies immer tun (da Sie GNU sedbereits verwenden ( -i)):

sed -i -f - FILE_NAME << EOF
s/BASE_64/$BASE_64/g
EOF

-f -sagt sed, dass das sed-Skript von stdin gelesen werden soll.

Wenn Sie das gleiche Skript für mehrere Dateien wieder zu verwenden, auf Linux (und nur Linux), mit einer Schale wie bash, zsh, kshdass die Geräte hier Dokumente mit temporären Dateien (im Gegensatz zu Rohren entgegengesetzt wie dashoder yash) und immer noch mit GNU sed, könnten Sie tun:

find . -name '*.conf' -exec sed -i -f /dev/stdin {} + << EOF
s/BASE_64/$BASE_64/g
EOF

Unter Linux (und nur unter Linux) /dev/stdinbedeutet dies nicht, dass stdin auf die gleiche Weise -funktioniert. Stattdessen ist es ein Symlink zu der auf stdin geöffneten Datei. Jedes Mal sed, wenn sie geöffnet wird, wird die Datei von Anfang an neu geöffnet. Der obige Befehl würde auf anderen Systemen (mit /dev/stdin) oder mit Shells, die hier Dokumente mit Pipes implementieren, einwandfrei funktionieren, jedoch nur, wenn nur wenige confDateien vorhanden sind, seddie nur einmal aufgerufen werden. Wenn das zweite Mal aufgerufen, auf Nicht-Linux - Systemen, wie mit -f -, /dev/stdinscheint leer , da es bereits durch den ersten Aufruf gelesen wurde.

busybox sedunterstützt -iauf die gleiche Weise wie GNU sed, unterstützt jedoch nicht -f -. Sie möchten -f /dev/stdines also auf jeden Fall dort verwenden. sedVerwenden Sie mit FreeBSD :

sed -i '' -f /dev/stdin FILE_NAME << EOF
s/BASE_64/$BASE_64/g
EOF
Stéphane Chazelas
quelle
4

Eine andere Möglichkeit wäre, zu ersetzen , sedmit edund speichern Sie Ihre Befehle in einer Datei. Zum Beispiel, wenn Sie ed_cmdsmit folgenden Inhalten erstellen :

%s/BASE_64/<expanded variable>/g
w
q

du könntest dann rennen

< ed_cmds ed FILE_NAME

und es würde die gewünschten Änderungen vornehmen, sodass Sie anstelle der Einstellung $BASE_64die Befehlsdatei ed erstellen würden.

Ed Erklärung

  • % bedeutet, den Befehl auf jede Zeile der Datei anzuwenden
  • s/pat1/pat2/gErsatzvorkommen von pat1mit pat2und gam Ende macht es für jedes Spiel auf der Linie, nicht nur für das erste
  • w Schreiben Sie die Änderungen auf die Festplatte
  • q Beenden (was passieren würde, wenn es sowieso EOF bekommen würde)

Natürlich können Sie Ihre sedBefehle in eine Datei einfügen und auch verwenden. -fWenn Sie dies jedoch tun und die Datei an Ort und Stelle ändern möchten, können Sie sie auch verwenden, edanstatt eine temporäre Datei zu erstellen und sie wie sed -ifolgt zu verschieben.

Eric Renouf
quelle
Können Sie mir bitte ein Beispiel für die obige Lösung geben? Ich habe das gleiche Problem mit sed. Da ich neu in der Shell bin, weiß ich nicht, wie man eine ed_cmds-Datei erstellt
springbootlearner
2

Die Größe der Base64-Darstellung der Datei ($ BASE_64) ist zu lang und überschreitet die maximale Argumentgröße. Sie sollten in der Lage sein, dieses Limit für Ihr System zu sehen, indem Sie es ausführen

getconf ARG_MAX

Sie müssen den ARG_MAXWert vergrößern . Aber ich denke, wenn die Datei zu groß ist, müssen Sie einen anderen Ansatz verwenden, um diesen Ersatz durchzuführen. Wenn ein Python-Skript es für Sie tun würde, würde ich es auch damit versuchen.

Labyrinthe
quelle
Vielen Dank. Ich werde mit einem Python-Skript gehen, wenn es keine andere Lösung gibt.
Lorenzo B
Beachten Sie, dass insbesondere Linux eine fest codierte Grenze für die Länge eines einzelnen Befehlszeilenarguments hat, sodass das Erhöhen ARG_MAXdort nicht einmal hilft.
Ilkkachu
2

Am Ende habe ich die sedAnweisungen in eine Datei geschrieben

SEDCOMMANDS=`tempfile`

und angerufen

sed -f "$SEDCOMMANDS" -- "$FILE_NAME"

Das ist gut, wenn Sie nicht verwenden sed -i. Wenn Sie die Datei an Ort und Stelle bearbeiten möchten, folgen Sie https://unix.stackexchange.com/a/284188/149867 und fügen Sie die entsprechenden edAnweisungen in eine Datei ein, gefolgt von wund q.

Cayhorstmann
quelle
-ifunktioniert gut mit -f. Stellen Sie nur sicher, dass Sie -i -f(oder -i '' -fmit BSD sed) verwenden, nicht -if. Sie können auch verwenden-f - , um die temporäre Datei zu vermeiden.
Stéphane Chazelas