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

9

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 executo compgen -b on bash 4.4 , recebo uma lista de todos os comandos internos do shell. Eu vejo, por exemplo, que [ e kill estão listados como sendo shell builtins. Mas suas localizações reais são:

/usr/bin/[
/bin/kill

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

    
por chevallier 10.05.2018 / 10:21

2 respostas

13

Os comandos que são construídos no shell são frequentemente construídos devido ao aumento de desempenho que isso causa. Chamar o external printf , por exemplo, é mais lento do que usar o construído em printf .

Como alguns utilitários não precisam ser incorporados, a menos que sejam especiais, como cd , eles também são fornecidos como utilitários externos . Isso é para que os scripts não quebrem se forem interpretados por um shell que não forneça um equivalente interno.

Alguns built-ins de shell também fornecem extensões para o comando equivalente externo. O printf do Bash, por exemplo, é capaz de fazer

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

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

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

printf '%s\n' *
Portanto,

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

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

enable -n printf

Existe uma pequena lista de utilitários que precisam para serem construídos em um shell (extraído do padrão POSIX lista de built-ins especiais )

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

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

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

Since cd affects the current shell execution environment, it is always provided as a shell regular built-in. If it is called in a subshell or separate utility execution environment, such as one of the following:

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

it does not affect the working directory of the caller's environment.

Estou, portanto, assumindo que os built-ins "especiais" não podem ter contrapartes externas, enquanto cd teoricamente poderia ter (mas não faria muito).

    
por 10.05.2018 / 10:35
7

Você está (muito compreensivelmente) confuso com o fato de que alguns builtins existem ambos como builtins e como comandos externos. Então, enquanto você está certo de que, por exemplo, existe um comando /bin/[ , isso não significa que sua "localização real" esteja em /bin .

Qualquer maneira fácil de testar isso é executar type com a opção -a , 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/sbin e /bin são todos links simbólicos apontando para /usr/bin , portanto, há 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 acontece com vários outros recursos internos do shell. No entanto, isso não altera o fato de que eles também são construídos em shell, compilados no próprio shell.

    
por 10.05.2018 / 11:17