Comprensione dei comandi integrati nella shell


12

Nel manuale di Bash , è scritto che

Builtin commands are contained >>> within <<< the shell itself

Inoltre, questa risposta afferma che

A built-in command is simply a command that the shell carries out itself,
instead of interpreting it as a request to load and run some
>>> other program <<<

Quando eseguo compgen -bsu bash 4.4, ricevo un elenco di tutti i comandi builtin di shell. Vedo ad esempio quello [e killsono elencati come builtin della shell. Ma le loro posizioni reali sono:

/usr/bin/[
/bin/kill

Ho pensato che essere un builtinmezzo per compilare il comando /bin/bashnell'eseguibile. Quindi cosa mi confonde davvero: per favore correggimi, ma come può un comando separato essere un builtin, quando in realtà non fa parte della shell?


1
Alcuni comandi esistevano originariamente come utility separate. La loro presenza ora è per conformità standard POSIX, portabilità e retrocompatibilità. Le conchiglie ne implementano alcune come integrate per le prestazioni. Potrebbero esserci altri motivi, ma questo è tutto senza troppi dettagli.
Sergiy Kolodyazhnyy,

1
Un altro motivo che mi viene in mente è perché alcuni comandi integrati sono necessari per la shell in modo specifico, ad esempio execper manipolare i descrittori di file e eval per la valutazione dei comandi. Non sono necessari come comandi autonomi
Sergiy Kolodyazhnyy

Risposte:


16

I comandi integrati nella shell sono spesso integrati a causa dell'aumento delle prestazioni che questo dà. Chiamare l' esterno printf , ad esempio, è più lento dell'uso incorporato printf.

Poiché alcune utility non devono essere integrate, a meno che non siano speciali, come cd, sono anche fornite come utility esterne . Questo in modo che gli script non si rompano se vengono interpretati da una shell che non fornisce un equivalente incorporato.

Alcuni built-in della shell forniscono anche estensioni al comando equivalente esterno. Bash's printf, per esempio, è in grado di fare

$ printf -v message 'Hello %s' "world"
$ echo "$message"
Hello world

(stampa su una variabile) che l'esterno /usr/bin/printfsemplicemente non sarebbe in grado di fare poiché non ha accesso alle variabili della shell nella sessione di shell corrente (e non può cambiarle).

Le utility integrate non hanno inoltre la limitazione che la loro riga di comando estesa deve essere più corta di una certa lunghezza. fare

printf '%s\n' *

è quindi sicuro se printfè un comando integrato della shell. La restrizione sulla lunghezza della riga di comando deriva dalla execve()funzione di libreria C utilizzata per eseguire un comando esterno. Se la riga di comando e l'ambiente corrente sono più grandi dei ARG_MAXbyte (vedere getconf ARG_MAXnella shell), la chiamata a execve()fallirà. Se l'utilità è integrata nella shell, execve()non è necessario chiamarla.

Le utility integrate hanno la precedenza sulle utility trovate in $PATH. Per disabilitare un comando integrato bash, utilizzare ad es

enable -n printf

C'è un breve elenco di utility che devono essere integrate in una shell (presa dall'elenco di incorporamenti speciali dello standard POSIX )

break
colon (:)
continue
dot (.)
eval
exec
exit
export
readonly
return
set
shift
times
trap
unset

Questi devono essere integrati poiché manipolano direttamente l'ambiente e il flusso del programma della sessione di shell corrente. Un'utilità esterna non sarebbe in grado di farlo.

È interessante notare che cdnon fa parte di questo elenco, ma POSIX afferma quanto segue :

Poiché cdinfluisce sull'attuale ambiente di esecuzione della shell, viene sempre fornito come un normale built-in della shell. Se viene chiamato in una subshell o in un ambiente di esecuzione dell'utilità separato, come uno dei seguenti:

(cd /tmp)
nohup cd
find . -exec cd {} \;

non influisce sulla directory di lavoro dell'ambiente del chiamante.

Suppongo quindi che gli incorporamenti "speciali" non possano avere controparti esterne, mentre cdin teoria potrebbe esserlo (ma non farebbe molto).


IIRC, chdir/ cderano binari esterni nei primissimi Unices / pre-Unix prima che forkfosse introdotto.
Xophmeister,

@Xophmeister Solaris 11.4 (beta) ha ancora /usr/bin/cd, ma in realtà non cambierà la directory di lavoro corrente. Il suo manuale dice: /usr/bin/cdnon ha alcun effetto sul processo di invocazione ma può essere utilizzato per determinare se una determinata directory può essere impostata come directory corrente.
Kusalananda

2
Un altro motivo piuttosto specifico per i builtin: builtin killè anche bello perché non ha bisogno di fork un altro processo, buono se hai raggiunto il limite del tuo numero di processi.
derobert,

7

Sei (molto comprensibilmente) confuso dal fatto che alcuni builtin esistono sia come builtin che come comandi esterni. Quindi, mentre hai ragione sul fatto che, ad esempio, esiste un /bin/[comando, ciò non significa che la sua "posizione effettiva" sia in /bin.

Un modo semplice per testarlo è eseguire typecon l' -aopzione che mostrerà tutte le istanze disponibili di un comando. Sul mio sistema Arch, mostra:

$ type -a [
[ is a shell builtin
[ is /sbin/[
[ is /usr/sbin/[
[ is /usr/bin/[

Nota che /sbin, /usr/sbine /bintutti i link simbolici puntano a /usr/bin, quindi c'è solo un esterno [:

$ readlink -f /usr/sbin /sbin /bin/
/usr/bin
/usr/bin
/usr/bin

Come puoi vedere, [è sia un comando incorporato che un comando esterno, e lo stesso vale per vari altri comandi incorporati della shell. Tuttavia, ciò non cambia il fatto che sono anche incorporati nella shell, compilati nella shell stessa.


perché distro. fornire un comando esterno separato per un comando interno già esistente? perché duplicano?
LoveWithMaths

1
@linuxuser alcune di queste utility sono richieste da POSIX e non puoi sapere se la shell che un utente sta usando stia fornendo anche un builtin. Non pensarli come comandi interni del sistema operativo, sono solo comandi interni della shell e la shell può cambiare.
terdon

Ho 1 dubbio ora, se i comandi interni sono forniti dalla shell; allora chi fornisce comandi esterni? come se avessi osservato molti comandi disponibili sia come comandi interni che esterni, ma non li ho installati esplicitamente; quindi chi fornisce un comando esterno? Distro li fornisce corretti?
LoveWithMaths

@linuxuser dipende dal comando e dal sistema operativo. Ad esempio, sul mio Arch Linux, /bin/printfè installato dal coreutilspacchetto e /bin/killda util-linux.
terdon

Mi dispiace ma non sono ancora chiaro, quale di cui sopra è fornito dalla distribuzione? e che dire dell'altro che non è fornito dalla distribuzione allora chi lo fornisce.
LoveWithMaths
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.