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:
-
Os relatórios de progresso / informações de registro pertencem a stderr ou stdout?
-
Quando usar o fluxo de erro padrão no aplicativo de linha de comando?
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.