Lange Rede, kurzer Sinn: Ich möchte nachverfolgen, wie einige ausführbare Dateien aufgerufen werden, um das Systemverhalten zu verfolgen. Angenommen, ich habe eine ausführbare Datei:
/usr/bin/do_stuff
Und es wird tatsächlich über Symlink unter verschiedenen Namen aufgerufen:
/usr/bin/make_tea -> /usr/bin/do_stuff
/usr/bin/make_coffee -> /usr/bin/do_stuff
und so weiter. Es do_stuff
ist klar, dass das erste Argument, das es erhält, verwendet wird, um zu bestimmen, welche Aktion tatsächlich ausgeführt wird, und der Rest der Argumente wird vor diesem Hintergrund behandelt.
Ich würde gerne jemals einen Anruf aufzeichnen /usr/bin/do_stuff
(und die vollständige Liste der Argumente). Wenn es keine Symlinks gäbe, würde ich einfach do_stuff
zu do_stuff_real
einem Skript gehen und es schreiben
#!/bin/sh
echo "$0 $@" >> logfile
/usr/bin/do_stuff_real "$@"
Da ich jedoch weiß, dass der Name, unter dem es aufgerufen wird, überprüft wird, funktioniert dies nicht. Wie schreibt man ein Skript, um dasselbe zu erreichen und trotzdem an do_stuff
den richtigen 'ausführbaren benutzten Namen' weiterzugeben ?
Um Antworten in diesen Zeilen zu vermeiden:
- Ich weiß, dass ich es in C machen kann (mit execve), aber es wäre viel einfacher, wenn ich in diesem Fall nur ein Shell-Skript verwenden könnte.
- Ich kann nicht einfach durch
do_stuff
ein Protokollierungsprogramm ersetzen .
quelle
sh
können Siemybase=${0##*/}
anstelle des Basisnamens verwenden.basename
Aufruf wiebasename -- foo.bar
ist mir unbekannt, und auf dem Linux-System, auf dem ich ihn getestet habe, wird das Ergebnis erzeugt, dasfoo.bar
das Skript beschädigen würde. Sind Sie sicher, dass dies eine gängige Methode ist?basename -- foo.bar
kehrt zurückfoo.bar
,basename -- --foo--/bar
kehrtbar
wie erwartet zurück.basename "$foo"
funktioniert nur, wenn Sie garantieren können, dass$foo
es nicht mit einem beginnt-
. Die allgemeine Syntax zum Aufrufen eines Befehls mit beliebigen Argumenten lautetcmd -x -y -- "$argument"
.cmd "$argument"
ist falsch, es sei denn du meinstcmd "$option_or_arg"
. Einige Befehle (einschließlich einiger historischer Implementierungen vonbasename
) werden jetzt nicht unterstützt,--
sodass Sie manchmal zwischen Portabilität und Zuverlässigkeit wählen müssen.Sie können verwendet werden
exec -a
(wie gefunden inbash
,ksh93
,zsh
,mksh
,yash
aber nicht POSIX noch) , die verwendet wird , ein , um anzugeben ,argv[0]
um einen Befehl wird ausgeführt:Beachten Sie, dass dies nicht der Befehl
$0
ist , denargv[0]
der Befehl empfängt. Es ist der Pfad des Skripts, an den übergeben wirdexecve()
(und der als Argument übergeben wirdbash
), aber das reicht wahrscheinlich für Ihren Zweck aus.Wenn beispielsweise Folgendes
make_tea
aufgerufen wurde:Wie eine Shell normalerweise beim Aufrufen des Befehls nach Namen (Nachschlagen der ausführbaren Datei in
$PATH
) tun würde, würde der Wrapper Folgendes tun :Das ist nicht:
aber das ist gut genug, da
do_stuff_real
es Tee machen soll.Wo das ein Problem wäre, wäre, wenn
do_stuff
aufgerufen würde als:wie das übersetzt werden würde zu:
Das würde im normalen Betrieb nicht passieren, aber beachten Sie, dass unser Wrapper so etwas tut.
Auf den meisten Systemen geht das
argv[0]
an das Skript übergebene Element verloren, sobald der Interpreter (hier/bin/bash
) ausgeführt wird ( derargv[0]
Interpreter auf den meisten Systemen ist der in der She-Bang-Zeile angegebene Pfad ), sodass ein Shell-Skript nichts dagegen tun kann.Wenn Sie das weitergeben
argv[0]
möchten, müssen Sie eine ausführbare Datei kompilieren. Etwas wie:quelle
perl
oderpython
falls verfügbar machen. Ältere Versionen vonzsh
wurden nicht unterstütztexec -a
, können aberARGV0=the-argv-0 cmd args
stattdessen immer verwendet werden.zsh
(obwohl Sie jetzt klar gemacht haben, dass Sie es nicht getan haben), aber es zu alt war, könnten Sie es trotzdem verwendenARGV0
.