Existe um padrão como os comandos que iniciam outros comandos tratam construções de shell como redirecionamentos?

1

Existe uma maneira fácil de fazer os seguintes comandos?

watch foo 2>/dev/null | tr ' ' '-'
strace foo 2>/dev/null | tr ' ' '-'
something_else foo 2>/dev/null | tr ' ' '-'    

Existe uma expectativa comum de como something_else deve se comportar? Existem construções de shell que podem desambiguar esses comandos (como qual saída do programa é redirecionada)?

    
por sevo 15.08.2018 / 22:20

2 respostas

1

TL; DR:

Is there a common expectation how something_else should behave?

Sim, como um comando normal. O shell não entende command1 command2 como dois comandos, é um comando e um argumento (mesmo que possa ser um nome de um binário válido encontrado em /bin , por exemplo). É o command1 que depois executa command2 via exec() syscall, não o shell.

Are there shell constructs that can disambiguate these commands (like which program's output is redirected)

Não, someting_else não seria tratado de maneira especial. Como dito acima, não há outra construção além de um comando e um argumento. Também parece que a confusão nesta questão é que ambos strace e foo são assumidos como sendo executados pelo shell, mas na verdade é uma cadeia de processos pai-filho.

Como o shell processa comandos e redirecionamentos

Cascas semelhantes a Bourne ( bash , dash , ksh ) seguem as regras POSIX sobre como os comandos são interpretados. POSIX especifica : 'Um' comando simples "é uma sequência de atribuições de variáveis opcionais e redirecionamentos , em qualquer seqüência, opcionalmente seguido por palavras e redirecionamentos, terminados por um operador de controle. Isso pode ser colocado em uma forma:

[VAR=foo BAR=baz] command1 [arg1, arg2...] [ n>m ]

A regra geral é que o redirecionamento se aplica a um comando, o que deixaria a maioria das palavras sem atribuição. No seu exemplo, strace é o comando e foo é o argumento para strace . Os redirecionamentos se aplicam apenas ao comando, não aos argumentos, que são strace . O foo não é executado pelo shell, mas por strace , caso em que foo se torna um processo filho de strace . Da mesma forma, somethingelse seria tratado como um comando com foo como argumento.

Descritores de arquivos

No que diz respeito aos comandos não incorporados, eles são um processo filho do shell, e processos filhos herdam os descritores de arquivos do shell, portanto eles geralmente não gerenciam redirecionamentos - eles recebem destinos "pré-empacotados", portanto como strace e 2>/dev/null ir, provavelmente não se importaria com o que o descritor de arquivo 2 realmente é (a menos que esteja verificando ativamente no nível do código-fonte). strace ainda gravará a saída no descritor de arquivo 2, mas o shell já instalou esse descritor de arquivo para apontar para /dev/null .

Como os descritores de arquivo são herdados, isso também explica por que, se você fizer algo como strace stat noexist 2>stracelog.txt , os dois fluxos de erro de strace e stat entrarão no mesmo arquivo. Por outro lado, alguns comandos permitem especificar explicitamente o destino como uma das suas opções. Assim, com strace -o tracelog.txt stat noexist 2>stracelog.txt , você só tem saída de stat no arquivo stracelog.txt - mesmo que o descritor de arquivo seja herdado, agora -o flag é a propriedade de strace e a saída é gerenciada pelo comando mesmo se o descritor de arquivo é herdado.

Isso também nos dá uma pequena dica: em teoria comandos poderiam "redirecionar" no sentido de duplicar descritores de arquivos para os existentes via dup2() syscall, que é exatamente o mesmo mecanismo que os shells usariam, mas até > de tipos de símbolos de redirecionamento - que ainda estão sob controle de shell e, portanto, apenas interpretados pelo shell pai.

Por que 2 > / dev / null?

Geralmente é aceito que a saída de diagnóstico vai para stderr . Na verdade, já temos dois excelentes posts sobre esse assunto:

watch e strace em seus exemplos seguem a convenção, isso é tudo. Não há nenhum requisito em si para especificar 2>/dev/null para ocultar a saída de tais comandos.

Se você quiser especificar redirecionamentos para o comando que você passa como um argumento, para strace , por exemplo, você precisaria ter um shell em torno dele. Por exemplo,

strace -f bash -c 'stat /etc/passwd nonexisting 2>/dev/null'

Observe o uso de -f flag, pois se o seu foco estiver no comando syscalls conforme aplicado ao comando stat , talvez você não os veja sem -f flag.

    
por 15.08.2018 / 23:10
2

Os comandos em si não lidam com os redirecionamentos. Quando o shell cria um novo processo no qual executar o comando, o shell configurará o IO como indicado. O comando em si é executado sem ter que se preocupar com isso.

Seu comando something_else apenas emitirá a saída para stdout e stderr como de costume.

    
por 15.08.2018 / 23:03

Tags