2015-04-09 10 views
6

Ich versuche ein Skript zu reparieren, das echo verwendet, das den eingebauten Befehl anstelle des Befehls verwendet, wie kann ich das verhindern?Wie verhindere ich, dass bash einen eingebauten Befehl verwendet?

Ich weiß, dass ich /bin/echo tun kann, um die Verwendung dieser zu erzwingen, aber ich möchte den Pfad (für Portabilität) nicht fest codieren.

dachte ich, etwas wie mit:

$ECHO=`which echo` 
$ECHO -e "text\nhere" 

aber which echo kehrt: "echo: Shell integrierten Befehl".


Ich habe eine echo Funktion am Ende definieren, die env als @Kenster empfiehlt verwendet. Auf diese Weise muss ich die Aufrufe von echo im Skript nicht ändern.

echo() { 
    env echo $* 
} 

# the function is called before the built-in command. 
echo -en "text\nhere" 
+1

'der eingebaute Befehl anstelle des Befehls' WTF? – ForceBru

+0

Warum nicht gleich etwas anderes nennen? –

+0

@El_Hoy: Nur neugierig, wie ist das interne Echo in Ihrem Szenario schlechter als "/ bin/echo"? –

Antwort

5

Verwenden Sie das Programm env. Env ist ein Befehl, der ein anderes Programm mit einer möglicherweise geänderten Umgebung startet. Da env ein Programm ist, hat es keinen Zugriff auf Shell-Builtins, Aliase und Ähnliches.

Dieser Befehl wird das Echo-Programm, die Suche nach ihm in Ihrem Befehlspfad läuft:

$ env echo foo 

Sie können dies überprüfen, indem Sie strace zu überwachen Systemaufrufe während des Laufens echo vs env echo:

$ strace -f -e trace=process bash -c 'echo foo' 
execve("/bin/bash", ["bash", "-c", "echo foo"], [/* 16 vars */]) = 0 
arch_prctl(ARCH_SET_FS, 0x7f153fa14700) = 0 
foo 
exit_group(0)       = ? 

$ strace -f -e trace=process bash -c 'env echo foo' 
execve("/bin/bash", ["bash", "-c", "env echo foo"], [/* 16 vars */]) = 0 
arch_prctl(ARCH_SET_FS, 0x7f474eb2e700) = 0 
execve("/usr/bin/env", ["env", "echo", "foo"], [/* 16 vars */]) = 0 
arch_prctl(ARCH_SET_FS, 0x7f60cad15700) = 0 
execve("/usr/local/sbin/echo", ["echo", "foo"], [/* 16 vars */]) = -1 ENOENT (No such file or directory) 
execve("/usr/local/bin/echo", ["echo", "foo"], [/* 16 vars */]) = -1 ENOENT (No such file or directory) 
execve("/usr/sbin/echo", ["echo", "foo"], [/* 16 vars */]) = -1 ENOENT (No such file or directory) 
execve("/usr/bin/echo", ["echo", "foo"], [/* 16 vars */]) = -1 ENOENT (No such file or directory) 
execve("/sbin/echo", ["echo", "foo"], [/* 16 vars */]) = -1 ENOENT (No such file or directory) 
execve("/bin/echo", ["echo", "foo"], [/* 16 vars */]) = 0 
arch_prctl(ARCH_SET_FS, 0x7f0146906700) = 0 
foo 
exit_group(0)       = ? 
+0

Ich habe am Ende Ihre Lösung verwendet, aber mit einer Funktion, um die Implementierung zu vereinfachen: 'echo() {env echo $ *}' hat super funktioniert! – eloyesp

6

Sie können das integrierte Echo deaktivieren:

enable -n echo 

Jetzt einfach wird die externe Version ausführen. Es wirkt sich nur auf den aktuellen Skriptprozess aus, sodass Sie es in Ihren Skripts problemlos ausführen können.

+0

Cool, das wusste ich nicht. Ist 'enable' ein eingebauter Befehl? Funktioniert es in 'sh'? – eloyesp

+2

'enable' ist eine eingebaute bash (es sei denn, Sie aktivieren' n enable', natürlich!). Es funktioniert nicht in POSIX 'sh', weil POSIX keine wirkliche Vorstellung von eingebaut vs extern hat. –

+0

Das erste, was mir in den Sinn kam, als ich 'builtin' und' enable' zusammen war, war 'enable -n enable': D. – Samveen