Das echo
In coreutils
scheint allgegenwärtig zu sein, aber nicht jedes System wird es (normalerweise /bin/echo
) am selben Ort haben . Was ist der sicherste Weg, dies aufzurufen, echo
ohne zu wissen, wo es ist?
Ich bin damit zufrieden, dass der Befehl fehlschlägt, wenn die Coreutils- echo
Binärdatei nicht auf dem System vorhanden ist - das ist besser, als etwas anderes wiederzugeben, als ich möchte.
Hinweis: Die Motivation ist es, das zu finden , echo
binär, nicht eine Reihe von Argumenten zu finden , wo jeder Shell echo
builtin konsistent ist. Es scheint keine Möglichkeit zu geben, nur einen Bindestrich über das integrierte Echo sicher zu drucken, ohne zu wissen, ob Sie sich in zsh
oder befinden bash
.
linux
echo
coreutils
portability
mgiuffrida
quelle
quelle
printf
).env echo ...
wird es finden und aufrufen (es sei denn, es gibt ein ernstes Problem, z. B. mit PATH)env
nicht in$PATH
ist eine Fehlerbedingung, die sehr schnell bemerkt werden würde.Antworten:
Beachten Sie, dass
coreutils
es sich um ein Softwarepaket handelt, das vom GNU-Projekt entwickelt wurde, um eine Reihe von Unix-Basisdienstprogrammen für GNU-Systeme bereitzustellen. Sie werden nur finden coreutilsecho
aus der Box auf GNU - Systemen (Debian
,trisquel
,Cygwin
,Fedora
,CentOS
...). Auf anderen Systemen finden Sie eine andereecho
Implementierung (im Allgemeinen mit einem anderen Verhalten als eine der am wenigsten portablen Anwendungen). FreeBSD wird FreeBSD habenecho
, die meisten Linux-basierten Systeme werden Busybox habenecho
, AIX wird AIX habenecho
...Einige Systeme verfügen sogar über mehrere (wie
/bin/echo
und/usr/ucb/echo
unter Solaris (letzteres ist Teil eines Pakets, das in späteren Versionen von Solaris jetzt optional ist, wie das for GNU-Dienstprogrammpaket, von dem Sie a erhalten würden/usr/gnu/bin/echo
), alle mit unterschiedlichen CLIs).GNU
coreutils
hat portiert zu den meisten Unix-ähnlichen (und sogar Nicht-Unix-artigen wie MS Windows - Systeme), so würden Sie in der Lage sein , zu kompilierencoreutils
'echo
auf den meisten Systemen, aber das ist wahrscheinlich nicht das, was Sie suchen.Beachten Sie auch, dass Sie Inkompatibilitäten zwischen Versionen von feststellen
coreutils
echo
(zum Beispiel, mit denen\x41
Sequenzen nicht erkannt wurden-e
) und dass das Verhalten von der Umgebung (POSIXLY_CORRECT
Variable) beeinflusst werden kann.Nun, die laufen
echo
aus dem Dateisystem (durch ein Look-up gefunden von$PATH
), wie für jede andere builtin, die typische Art und Weise ist mitenv
:In
zsh
(wenn Sie keine anderen Shells emulieren) können Sie auch Folgendes tun:ohne einen zusätzlichen
env
Befehl ausführen zu müssen .Ich hoffe jedoch, dass der obige Text deutlich macht, dass er in Bezug auf die Portabilität nicht hilfreich sein wird. Verwenden Sie
printf
stattdessen Portabilität und Zuverlässigkeit .quelle
env
Ich habe nicht daran gedacht, aber es ist genau das, was ich will, obwohl ich im Allgemeinenprintf
über verwenden werdeecho
.Ich denke, das ist eine schlechte Idee, um ehrlich zu sein, aber dies wird einen ziemlich soliden Job machen, um die Coreutils
echo
in einer vernünftigen Umgebung zu finden. Das sind POSIX-kompatible Befehle der ganzen Weg durch (getconf
,find
,sh
,grep
,strings
,printf
,head
), so sollte es überall gleich verhalten. Dasgetconf
gibt uns die POSIX-kompatiblen Versionen jedes dieser Tools zuerst im Pfad, in Fällen, in denen die Standardversionen nicht dem Standard entsprechen.Es findet jede ausführbare Datei , die beide druckbare strings „GNU coreutils“ und „Echo der Saite (n) auf der Standardausgabe“, die in dem GNU erscheinen enthält
echo
‚s ---help
Ausgang und sind buchstäblich im Programmtext. Wenn es mehr als eine Kopie gibt, wählt sie willkürlich die erste aus, die sie gefunden hat. Wenn keine gefunden wird, schlägt dies fehl - die wird$(...)
zu einer leeren Zeichenfolge erweitert.Ich würde es jedoch nicht als "sicher" bezeichnen, da das Vorhandensein dieses (ausführbaren) Skripts irgendwo auf dem System einige Probleme verursachen würde:
Um es noch einmal zu wiederholen, ich denke, das ist eine sehr schlechte Idee. Es
echo
gibt keine vernünftige, tragbare Möglichkeit, eine bestimmte Version davon zu finden , die auf unbekannten Systemen sicher ausgeführt werden kann. Irgendwann müssen Sie etwas ausführen, das auf einer Vermutung basiert.Ich würde Sie ermutigen, stattdessen den
printf
Befehl zu verwenden , der ein Format und alle Argumente akzeptiert, die Sie wörtlich verwenden möchten.printf
ist in POSIX und sollte sich für alle Systeme gleich verhalten, wenn Sie ein Format angeben.quelle
grep -q
mitgrep .>/dev/null
. Wenn Sie unter laufen müssenbusybox-w32
, gibt es auch die FrageNUL
statt/dev/null
an diesem Punkt ... Oder Sie machen einige Hacks, um die Ausgabe durch Piping zu lesen und wegzuwerfen, und erfordern noch mehr Hacks, um dengrep
Exit-Status nicht zu verlieren . Die Portabilität von Shell-Skripten ist die Hölle . :)strings
ist wirklich nicht sicher, ob es installiert wird, da es meiner Erfahrung nach auf vielen minimaleren Systemen standardmäßig weggelassen wird. Trotzdem +1, denn wenn Sie wirklich sicher sein möchten, dass Sie dasecho
von gefunden habencoreutils
, ist die Aufgabe, Ihren gesamten Dateisystembaum nachecho
Instanzen zu durchsuchen und diese dann nach dem richtigen Hilfetext usw. zu durchsuchen, der einzig wirklich zuverlässige Weg, wenn Sie befinden sich in Systemen, in denenecho
Verhalten ein Problem darstellt.grep
(undsh
) in/usr/xpg4/bin
; Dafürgetconf
ist das da.strings
wird auch von POSIX benötigt, sodass ein System, das es nicht hat, nicht kompatibel ist. Es ist einfach nicht möglich, portabel für Systeme zu schreiben, bei denen beliebige Bits fehlen (möglicherweisegrep
nicht vorhanden!).Persönlich vermeide ich es
echo
vollständig in meinen Shell-Skripten und verwende es,printf '%s\n' blablabla
wenn die Zeichenfolge kurz ist, und dokumentiere hier, wenn die Zeichenfolge lang ist.Zitat aus §11.14 Einschränkungen von Shell Builtins des Autoconf- Handbuchs :
quelle
Ehrlich gesagt bin ich ziemlich zuversichtlich, dass es kein Problem gibt, das nicht besser gelöst werden kann, wenn man etwas anderes tut, als explizit eine externe Binärdatei aufzurufen (insbesondere nach einer bestimmten Implementierung einer externen Binärdatei zu suchen).
So sehr ich normalerweise Antworten hasse, die sich auf "Sie sollten niemals das tun müssen, was Sie tun möchten" beschränken, mache ich hier eine Ausnahme. Ich werde stattdessen zahlreiche Alternativen vorschlagen, in der Reihenfolge, wie stark ich sie vorschlage. Wenn Sie unbedingt die richtige
echo
Binärdatei finden müssen , hat Michael Homer die am besten geeignete Antwort, und Sie sollten auch die Antwort von Stéphane Chazelas lesen, da dadurch mehrere Speicherorte in einem Dateisystem angezeigt werden, von denen Sie möglicherweise nicht erwarten, dass sieecho
Binärdateien finden . Ich habe auch einige zusätzliche Einschränkungen bezüglich der Suche nach dem "richtigen" Echo in meinem letzten Abschnitt dieser Antwort.printf
Ich habe noch nie ein System gesehen, das eigentlich benutzerdefinierte Shell-Skripte ausführen sollte und das in den letzten Jahrzehnten eine echte Verwendung fand, das nicht mit einem ausgeliefert wurde
printf
. Ich habe sicherlich noch nie ein System gesehen, das auch nur annähernd so groß wie GNU warcoreutils
und nichtprintf
sofort ausgeliefert wurde.Aus Sicht der Perspektive bin ich so besessen davon, dass die Portabilität von Shell-Skripten ungesund ist, und ich habe derzeit Zugriff auf buchstäblich nur zwei Systeme mit einer Bourne-ähnlichen Shell, die keine haben
printf
: Ein virtualisiertes Unix v7 (ja, das von vier vor Jahrzehnten oder so) und ein (von ungefähr fünf in meinem Besitz) Android-Gerät, auf dem im Grunde nichts installiert ist und das so gesperrt ist, dass es sowieso bald keine nützlichen Shell-Skripte mehr ausführen wird.Dies wird Ihre Zeichenfolge genau auf - ich verspreche - jedes System drucken , das es verdient, in der heutigen Zeit von irgendjemandem verwendet zu werden:
und
AUSSER Sie müssen auch Null- Bytes ausdrucken . Ich bezweifle, dass du musst. Wenn Sie dies tun, können Sie ohnehin nicht den gesamten Text als ein Argument für printf verwenden , da die meisten Shells (hier verdient Lob) Null-Bytes als String-Terminatoren verwenden. Sie würden also oktale Escapezeichen in Ihrer Formatzeichenfolge (das erste Argument) verwenden und diese mit null oder mehr und null oder mehr weiteren Argumenten kombinieren, um den gesamten anderen Text zu drucken. Hex Escape (vs Octal) und andere Tricks sind meines Wissens weniger portabel.
zsh
\000
%s
Vorschlag: Fügen Sie nichts, was Sie nicht benötigen, speziell analysiert / in die Formatzeichenfolge konvertiert ein. Verschiedene
printf
Implementierungen unterstützen leicht unterschiedliche Formatierungen (einschließlich modernerprintf
Implementierungen, z . B.bash
eingebaute vsbusybox printf
).Wenn Sie möchten, dass die zusätzliche Zeilenumbruch an Ihre Ausgabe angehängt wird,
\n
ist es trivial, Ihrer Formatzeichenfolge eine zusätzliche hinzuzufügen:ist ein streng eindeutiges / funktioniert-das-überall-gleichwertiges Äquivalent von
Wenn Sie in eine komplizierte Situation geraten, in der es nicht einfach ist, die benötigte Formatzeichenfolge zu erstellen (denken Sie daran, dass Sie die Formatzeichenfolge auch programmgesteuert mithilfe von Variablen erstellen können), können Sie das Zeilenumbruchliteral jederzeit in die Argumente aufnehmen, an die Sie übergeben
printf
oder die Sie ausgeben Zeilenumbruchzeichen für sich mit einem bloßenecho
ohne Argumente separat.Here-Dateien oder:
cat <<DELIMITER
oder
Die einzige Einschränkung ist , dass Sie nicht kontrollieren können , wenn Sie eine neue Zeile am Ende bekommen oder nicht: Sie immer wird eine neue Zeile am Ende bekommen. Meistens ist dies wahrscheinlich das, was Sie wollten, oder es spielt keine Rolle. Außerdem verwenden viele (alle?) Shells temporäre Dateien auf der Festplatte, um Here-Dateien zu implementieren, sodass es möglich ist, dass ein sehr eingeschränktes System dies nicht zulässt (dieselbe obszön verkrüppelte Android-Instanz, ohne die
printf
ich auch SELinux habe Richtlinien oder andere Berechtigungsbeschränkungen (ich erinnere mich nicht genau), die verhindern, dass die Shell temporäre Dateien erstellt).Aus diesem Grund kann eine Here-Datei in einem Computer-Sicherheitshinweis, wenn Sie vertrauliche Informationen drucken müssen
echo
, je nach genauem System entweder schlechter oder besser sein als eine (istecho
extern oder eine integrierte? Is / proc / $ PID) Welt oder Benutzer lesbar? Sind hier Dateien Benutzer oder Welt lesbar?) und Ihr genaues Bedrohungsmodell (ist es wahrscheinlicher, dass Ihre Bedrohung Ihre Festplatte forensisch durchsucht als Ihre laufenden Prozessinformationen?)expr
Ein wenig bekanntes Merkmal von
expr
ist, dass es Teilzeichenfolgen aus einem Argument mit einer Regex-Übereinstimmung extrahieren und drucken kann. Dies ist im Grunde eine portablere Version des ursprünglichenecho
Verhaltens (wörtliche Druckinhalte und ein Zeilenumbruchzeichen) und eine noch portablere Methode zum Drucken von einfachem Text alsprintf
:und
Dies funktioniert zurück zu Unix v7. Die
X
Vorderseite sowohl der zu druckenden Zeichenfolge / Variablen als auch die Vorderseite des regulären Ausdrucks außerhalb der\( \)
Untermusterübereinstimmung / -auswahl ist wichtig: Ersteres verhindert, dass der Wert, den Sie drucken, vomexpr
Befehl als falsch interpretiert wirdexpr
Schlüsselwort, und letzteres stellt dann sicher, dass das X nicht tatsächlich gedruckt wird.awk
Hier ist ein kompakter
awk
Einzeiler, der die meisten einzeiligen Argumente druckt, die er eindeutig erhält (Sie haben immer noch ein Problem mit Backslashes in der neueren Version vonawk
- danke an Stephan, dass Sie mich in den Kommentaren daran erinnert haben):Dies funktioniert zurück zu Unix v7. Wenn Sie keine Backslashes haben, ist dies extrem portabel und möglicherweise gut genug für den Text, den Sie ausgeben müssen. Möglicherweise finden Sie auch das Schreiben von Feature-Tests für verschiedene
awk
Implementierungen in Ihren Skripten einfacher / einfacher / sauberer als dasecho
Arbeiten für Sie, da es zwar definitiv viele Abweichungen zwischenawk
s gibt, es jedoch weniger Variationen gibt, auf die getestet werden muss, alsecho
wenn Ihr Kernziel nur das Schreiben einiger ist genaue Ausgabe.Verwenden Sie natürlich die Zeichenfolgentechnik in einfachen Anführungszeichen, wenn Sie ein Literal anstelle einer Variablen verwenden möchten.
echo
Führen Sie ein Argument ohne Argumente aus, wenn Sie danach eine neue Zeile wünschen (oder nehmen Sie sich die Zeit, um eine bestimmte Methode genau zu überprüfen, um sicherzustellen, dass eine neue Zeile vomawk
Befehl gedruckt wird. Ich empfehle, den:
Befehl no-op links in der Pipe durchecho
Argumente ohne Argumente zu ersetzen. Aber ich habe diese Idee nicht sorgfältig auf ihre allgemeine Portabilität geprüft.echo
durchgeleitetsed
oder ähnlichWenn Sie wissen, dass Ihre Eingaben nichts Besonderes sind (es werden keine Oktal-Escapezeichen mit Backslashes wie
\000
in der Eingabe ausgegeben, die Sie buchstäblich drucken möchten, und Sie müssen nur vermeiden, ein-
Zeichen speziell zu analysieren , z. B. das Sie drucken möchten-e
, können Sie dennoch beliebigeecho
Arbeiten ausführen Wenn Sie etwas anderes haben, können Sie dieecho
Ausgabe vorverarbeiten :Bei begrenzten, genau definierten Eingaben können Sie möglicherweise mit einfachen
sed
Ersetzungen wie diesen davonkommen . Je nachdem, was genau Sie benötigen, wird es möglicherweise zunehmend schwieriger. Ab einem bestimmten Punkt ist es besser, mit der nächsten Alternative fortzufahren:Funktionstest
echo
Die Idee, dass Sie nicht zuverlässig
echo
genau das drucken können, was Sie wollen, wenn Sie bereit sind, sich Mühe zu geben, um dies zu tun, ist nicht unbedingt wahr, insbesondere wenn Sie über eine bekannte Reihe von Ausgaben verfügen, die Sie benötigen. Und glauben Sie mir, es wird weniger schmerzhaft sein, alsecho
irgendwo im Dateisystem nach der richtigen Binärdatei zu suchen .Sie haben insbesondere Bedenken geäußert, ein
-
Zeichen zuverlässig zu drucken . Leider habe ich noch kein gründlichesecho
Shell-Skript-Snippet zum Testen von Funktionen geschrieben, aber hier sind einige grundlegende Snippets, die mir auf den Kopf gefallen sind:Sie können ähnliche Tests für bestimmte Dinge
echo -e '\055'
erstellen : (sollte entweder ausgegeben werden-e \055
oder-
),echo -E '\055'
(wenn Backslash standardmäßig analysiert wird und Sie versuchen möchten, sie auszuschalten) usw.Viele moderne Echo-Instanzen analysieren andere Backslash-Escapezeichen als Oktalzahlen, aber Sie können entweder einen Feature-Test speziell für diese (
echo '\x2d'
oder was auch immer) durchführen - aber ich denke, in den meisten Fällen möchten Sie wirklich nur die Argumente finden, die Sie übergeben können Echo, damit es Dinge druckt, ohne spezielle Ersetzungen am Inhalt vorzunehmen, und dann die gewünschte Ausgabe wörtlich eingeben.Abhängig von Ihren Anforderungen
echo -n
lohnt es sich möglicherweise auch, einen Test durchzuführen. Beachten Sie jedoch, dass beim Ersetzen von Befehlen immer die letzte neue Zeile entfernt wird (nur die letzte bei den meisten Shells, aber alle nachfolgenden Zeilenumbrüche bei einigen Shells). Daher sind dies Ihre beiden wahrscheinlichen Ausgabeoptionen das Literal-n
und die leere Zeichenfolge.Vielleicht möchten Sie auch konsultieren
autoconf
undm4
Quellen, weil ich denke, dass diese Tools sich sehr bemühen, ein Echo zu finden, mit dem sie eindeutig drucken können, wenn sie keinprintf
oder etwas anderes finden, das funktioniert.Im wahrsten Sinne des Wortes alles andere
Ich denke wirklich, dass fast alles, was nicht davon abhängt, dass Sie brutal nach genau dem richtigen suchen müssen, das
echo
Beste ist. Es ist sehr wahrscheinlich, dass bestimmteecho
nicht installiert werden oder nicht dort installiert werden, wo Sie suchen, oder dass eine automatische Bruteforce-Suche ab beginnt/
das System eines armen Kerls zum Crawlen bringt.Und obwohl dies sehr unwahrscheinlich ist, ist es möglich, dass eine Binärdatei Ihren Fingerabdruck als GNU weitergibt
coreutils
echo
, aber einen Verhaltensunterschied aufweist: Selbst wenn GNU ihre Implementierung nie ändert, kann jemand seine eigene installierte Version von GNUs einpacken,echo
um nicht das zu tun, was er in Betracht zieht Seien Sie ein dummes Verhalten (das transparente Durchlaufen aller Argumente, mit Ausnahme des stillschweigenden Löschens der speziellen Argumente beim Festlegen der gewünschten Argumente, ist in einem Shell-Skript trivial, sodass Sie leichtecho --help
den richtigen Text drucken können,echo -e '\055'
aber das Falsche tun). Und nein, nicht einmal eine BinärdateiDas gründliche Fingerabdruckverfahren ist sicher: Ich habe zuvor rohe ELF-Binärdateien bearbeitet, um das Verhalten zu ändern, und ich werde es erneut tun. Manchmal geht es darum, sehr nützliche Funktionen zu aktivieren (Nachrichten, die keine ASCII-Bytes enthalten, wie Unicode-Smileys, in Closed-Source-Messaging-Software stillschweigend zu löschen) und manchmal um wirklich kleine Dinge wie das Ändern der fest codierten StandardeinstellungPS1
in Shells\$\
anstelle von\w \$
). Ich persönlich habe nicht genug Gründe, dies zu tun,echo
weil ich auf Systemen, die ich tatsächlich verwende,echo
bei fast allen ernsthaften Arbeiten einfach ignoriere , aber jemand anderes hat möglicherweise ein ebenso starkes Gefühl für das Standardverhaltenecho
wie für StandardvariablenwertePS1
. Sie kehren also zum Testen von Funktionen zurückecho
. An diesem Punkt finden Sie den obigen Abschnitt.Beachten Sie außerdem, dass ich Systeme habe, auf denen GNU-Coreutils
echo
installiert sindgecho
, sodass diese Systeme weder durch eine effiziente Suche nach denPATH
und wahrscheinlich installierten Speicherorten noch durch eine Bruteforce-Suche nach nur genannten Dateien abgefangenecho
werden.Und ich würde tatsächlich wetten, dass auf mehr Systemen eine Skriptsprache wie
perl
installiert installiert ist, die das kann, was Sie wollen, als auf Systemen, diecoreutils
echo
speziell über GNU verfügen : Einige Skriptsprachen sind allgegenwärtig und haben meistens eine Implementierung oder eine genau definierte Spezifikation, währendecho
Implementierungen dies sind unzählige und folgen Sie genau einer Spezifikation: "Machen Sie etwas anderes als so viele andereecho
Implementierungen wie möglich".quelle
awk
müssen SieENVIRON
(oderARGV
) verwenden, nicht mit dem V7 awk. Mitawk -v v="$v" ...
oderawk ... v="$v"
haben Sie Probleme mit Backslashes.awk
s zu erinnern .sed
ist eine nette Idee (obwohl ich hoffentlich nichts tun muss, was es wirklich erfordert). In Zukunft werde ich auf jeden Fall daran denken, dass "es kein Problem gibt, das nicht besser gelöst werden kann, wenn man etwas anderes tut als explizit ... eine bestimmte Implementierung einer externen Binärdatei aufzurufen".