Das Eintippen /usr/bin/env sed -f
des Terminals funktioniert.
Aber wenn man es als Schafskopf benutzt,
#!/usr/bin/env sed -f
s/a/b/
Das Skript kann nicht ausgeführt werden:
/usr/bin/env: sed -f: No such file or directory
Ich glaube irgendwie, dass es mit -f zusammenhängt. Aber wie lässt sich das beheben?
scripting
sed
executable
env
Cheng
quelle
quelle
Antworten:
Sie können tragbarerweise nicht mehr als ein Argument in eine
#!
Zeile setzen . Das bedeutet nur einen vollständigen Pfad und ein Argument (z. B.#!/bin/sed -f
oder#!/usr/bin/sed -f
) oder#!/usr/bin/env
kein Argument für den Interpreter.Eine Problemumgehung, um ein portables Skript zu erhalten, ist die Verwendung
#!/bin/sh
eines Shell-Wrappers, der das sed-Skript als Befehlszeilenargument übergibt. Beachten Sie, dass dies von POSIX nicht genehmigt wird (Multianweisungsskripte müssen aus Gründen der-e
Portabilität für jede Anweisung mit einem separaten Argument geschrieben werden ), aber es funktioniert mit vielen Implementierungen.Für ein langes Skript ist es möglicherweise praktischer, einen Heredoc zu verwenden. Ein Vorteil eines Heredocs ist, dass Sie die einzelnen Anführungszeichen nicht in Anführungszeichen setzen müssen, sofern vorhanden. Ein großer Nachteil ist, dass das Skript auf der Standardeingabe basiert, was zwei ärgerliche Folgen hat. Einige Versionen von sed erfordern
-f /dev/stdin
stattdessen-f -
, was ein Problem für die Portabilität darstellt. Schlimmer noch, das Skript kann nicht als Filter fungieren, da die Standardeingabe das Skript ist und nicht die Daten sein können.Der Nachteil des Heredocs kann durch eine sinnvolle Verwendung von behoben werden
cat
. Da dadurch das gesamte Skript wieder in der Befehlszeile angezeigt wird, ist es nicht POSIX-kompatibel, aber in der Praxis weitgehend portierbar.Eine andere Problemumgehung besteht darin, ein Skript zu schreiben, das sowohl von sh als auch von sed analysiert werden kann. Dies ist tragbar, einigermaßen effizient, nur ein wenig hässlich.
Erklärungen:
b
; Der Inhalt spielt keine Rolle, solange die Funktion syntaktisch korrekt aufgebaut ist (insbesondere können Sie keine leere Funktion haben). Wenn dies der Fall ist (dh immer), führen Siesed
das Skript aus.()
Label verzweigen , dann wohlgeformte Eingabe. Dann eini
Befehl, der keine Wirkung hat, weil er immer übersprungen wird. Schließlich das()
Etikett, gefolgt vom nützlichen Teil des Skripts.quelle
#!/usr/bin/env
und kein Argument." ist nicht sehr gut formuliert. Vielleicht "oder#!/usr/bin/env sed
und kein Argument zu sed."Abhängig vom Betriebssystem gibt es verschiedene inkompatible Implementierungen von shebang (#!). Einige erstellen eine vollständige Argumentliste, andere behalten den Befehlspfad bei und geben alle verbleibenden Argumente als ein einziges Argument an, andere ignorieren alle Argumente und übergeben nur den Befehlspfad, und andere übergeben die gesamte Zeichenfolge als ein einziges Argument Befehl. Sie scheinen im letzteren Fall zu sein.
quelle
env versucht eine Datei mit dem Namen "sed -f" zu finden. Sie können "#! / Usr / bin / sed -f" als Ihre Shebang-Zeile verwenden.
quelle
Ab GNU coreutils v8.30 können Sie Folgendes tun:
Diese Funktion wurde in einem kürzlich (2018.04.20) hinzugefügt begehen zu
env.c
in dem GNU coreutils - Paket, das die zusätzlichen-S
oder--split-string
Option.Von der
env
Manpage:Weitere Beispiele finden Sie im GNU coreutils-Handbuch .
Wenn Sie die
-v
Option auch für die ausführliche Ausgabe verwenden, können Sie genau sehen, wieenv
die Zeichenfolge der Argumente aufgeteilt wird:In
my_sed_script.sed
:Ausführung:
Hinweis: Dies gilt nur für Shebangs, die verwendet werden
/usr/bin/env
, da dies--split-string
eineenv
spezielle Funktion von GNU ist .quelle
Diese Antwort bietet einen Weg zu einer eleganten Lösung: /programming//a/1655389/642372
read
ein Heredoc in eine Shell-Variable.sed
.Probe:
quelle
Ich mag die Lösung von Walker, aber sie kann verbessert werden (in einer separaten Antwort, da Kommentare keinen vorformatierten Text akzeptieren). Dies funktioniert möglicherweise nicht unter allen Linux- oder Bash-Versionen, aber unter Ubuntu 17.10 können Sie dies auf Folgendes reduzieren:
Sie können
eval
denread
Befehl entfernen und vereinfachen , müssen jedoch den Kommentar im heredoc entfernen .Außerdem finden Sie unter http://www.grymoire.com/unix/sed.html ein nützliches Tutorial für alles, was Sie schon immer über sed wissen wollten, aber noch keine Fragen hatten . Dies schlägt eine noch bessere Lösung vor, auf Kosten des Verlusts
/usr/bin/env
und der Hardcodierung des Pfades zu sed:Dies hat den zusätzlichen Vorteil, dass mehr als ein
s///
Ersatz unterstützt wird.quelle