Noções básicas sobre comandos internos do shell

12

No manual do bash , está escrito que

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

Além disso, esta resposta afirma que

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 eu executar compgen -bem bash 4.4, recebo uma lista de todos shell builtin comandos. Vejo, por exemplo, que [e killestão listados como shell builtins. Mas suas localizações reais são:

/usr/bin/[
/bin/kill

Eu pensei que builtinisso significa que o comando é compilado no /bin/bashexecutável. Então, o que realmente está me confundindo: por favor, corrija-me, mas como um comando separado pode ser um builtin, quando na verdade não faz parte do shell?

manifestador
fonte
1
Alguns comandos existiam originalmente como utilitários separados. Sua presença agora é para conformidade com o padrão POSIX, portabilidade e compatibilidade com versões anteriores. Os shells implementam alguns como incorporados ao desempenho. Pode haver outro motivo, mas é isso sem muitos detalhes.
Sergiy Kolodyazhnyy
1
Outra razão pela qual pude pensar é porque alguns comandos internos são necessários especificamente para o shell, como execmanipular descritores de arquivos e eval avaliar os comandos. Eles não são necessários como comandos independentes #
Sergiy Kolodyazhnyy

Respostas:

16

Os comandos incorporados ao shell geralmente são incorporados devido ao aumento de desempenho que isso proporciona. Ligar para o externo printf , por exemplo, é mais lento do que usar o incorporado printf.

Como alguns utilitários não precisam ser integrados, a menos que sejam especiais, cdtambém são fornecidos como utilitários externos . Isso ocorre para que os scripts não sejam interrompidos se forem interpretados por um shell que não fornece um equivalente interno.

Alguns recursos internos do shell também fornecem extensões para o comando equivalente externo. Bash's printf, por exemplo, é capaz de fazer

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

(imprima em uma variável) que o externo /usr/bin/printfsimplesmente não seria capaz de fazer, pois não tem acesso às variáveis ​​do shell na sessão atual do shell (e não pode alterá-las).

Os utilitários incorporados também não têm a restrição de que sua linha de comando expandida tenha que ser menor que um determinado comprimento. Fazendo

printf '%s\n' *

portanto, é seguro se printffor um comando interno do shell. A restrição no comprimento da linha de comando vem da execve()função da biblioteca C usada para executar um comando externo. Se a linha de comando e o ambiente atual forem maiores que ARG_MAXbytes (veja getconf ARG_MAXno shell), a chamada para execve()falhará. Se o utilitário estiver embutido no shell, execve()não precisará ser chamado.

Utilitários incorporados têm precedência sobre os utilitários encontrados em $PATH. Para desativar um comando embutido bash, use, por exemplo

enable -n printf

Há uma pequena lista de utilitários que precisam ser incorporados ao shell (extraídos da lista de embutidos especiais do padrão POSIX )

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

Eles precisam ser integrados, pois manipulam diretamente o ambiente e o fluxo do programa da sessão atual do shell. Um utilitário externo não seria capaz de fazer isso.

Curiosamente, cdnão faz parte desta lista, mas o POSIX diz o seguinte sobre isso:

Como cdafeta o ambiente de execução atual do shell, ele sempre é fornecido como um built-in regular do shell. Se for chamado em um subshell ou ambiente de execução de utilitário separado, como um dos seguintes:

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

isso não afeta o diretório de trabalho do ambiente do chamador.

Portanto, estou assumindo que os "especiais" embutidos não podem ter contrapartes externas, enquanto cdna teoria poderiam ter (mas não faria muito).

Kusalananda
fonte
O IIRC chdir/ cderam binários externos nos primeiros Unices / pré-Unix antes de serem forkintroduzidos.
Xophmeister
O @Xophmeister Solaris 11.4 (beta) ainda possui /usr/bin/cd, mas na verdade não altera o diretório de trabalho atual. Seu manual diz: /usr/bin/cdnão tem efeito no processo de chamada, mas pode ser usado para determinar se um diretório pode ou não ser definido como o diretório atual.
Kusalananda
2
Outro motivo bastante específico para builtins: o builtin killtambém é bom porque não precisa bifurcar outro processo, bom se você atingir o limite de número de processos.
Derobert
7

Você está (muito compreensivelmente) confundido pelo fato de que alguns builtins existir tanto como builtins e como comandos externos. Portanto, enquanto você estiver certo de que, por exemplo, existe um /bin/[comando, isso não significa que sua "localização real" esteja /bin.

Qualquer maneira fácil de testar isso é executar typecom o -aswitch que mostrará todas as instâncias disponíveis de um comando. No meu sistema Arch, isso mostra:

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

Observe que /sbin, /usr/sbine /bintodos os links simbólicos estão apontando para /usr/binque haja apenas um externo [:

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

Como você pode ver, [é um comando interno e externo, e o mesmo se aplica a vários outros recursos internos do shell. No entanto, isso não muda o fato de que eles também são embutidos no shell, compilados no próprio shell.

terdon
fonte
porque distro. fornecer comando externo separado para um comando interno já existente? por que eles duplicam?
LoveWithMaths
1
@linuxuser Alguns desses utilitários são requeridos pelo POSIX, e você não pode saber se o shell que um usuário está usando também fornecerá um built-in. Não pense neles como comando interno do sistema operacional, eles são apenas comandos internos do shell, e o shell pode mudar.
terdon
Tenho uma dúvida agora, se comandos internos são fornecidos pelo shell; então quem fornece comandos externos? como eu observei muitos comandos disponíveis tanto como internos quanto externos, mas eu os instalei explicitamente; então quem fornece comando externo? Distro fornece-los corretos?
LoveWithMaths
O @linuxuser depende do comando e do sistema operacional. Por exemplo, no meu Arch Linux, /bin/printfé instalado pelo coreutilspacote e /bin/killpor util-linux.
terdon
Sinto muito, mas ainda não estou claro. Qual das opções acima é fornecida pela distro? e o outro que não é fornecido pela distro e quem a fornece.
LoveWithMaths