Não há "regras" como tal. Alguns programas recebem entrada de STDIN e outros não. Se um programa pode receber entrada de STDIN, pode ser canalizado para, se não, não pode.
Você pode dizer normalmente se um programa aceitará ou não a entrada, pensando sobre o que faz. Se o trabalho do programa for de alguma forma manipular o conteúdo de um arquivo (por exemplo, grep
, sed
, awk
etc.), ele normalmente recebe entrada de STDIN. Se o trabalho for manipular o arquivo em si (por exemplo, mv
, rm
, cp
) ou um processo (por exemplo, kill
, lsof
) ou para retornar informações sobre algo (por exemplo, top
, find
, ps
) então isso não acontece.
Outra maneira de pensar sobre isso é a diferença entre argumentos e entrada. Por exemplo:
mv foo bar
No comando acima, mv
não tem entrada como tal. O que foi dado é dois argumentos. Ele não sabe ou se importa com o que está em nenhum dos arquivos, ele apenas sabe quais são seus argumentos e deve manipulá-los.
Por outro lado
sed -e 's/foo/bar/' < file
--- -- ------------ ----
| | | |-> input
| | |------------> argument
| |--------------------> option/flag/switch
|------------------------> command
Aqui, sed
recebeu entrada e também um argumento. Uma vez que é necessário inserir, ele pode lê-lo a partir de STDIN e pode ser canalizado para.
Fica mais complicado quando um argumento pode ser a entrada. Por exemplo
cat file
Aqui, file
é o argumento que foi dado a cat
. Para ser preciso, o arquivo nome file
é o argumento. No entanto, como cat
é um programa que manipula o conteúdo dos arquivos, sua entrada é o que estiver dentro de file
.
Isso pode ser ilustrado usando strace
, um programa que rastreia as chamadas do sistema feitas por processos. Se executarmos cat foo
via strace
, poderemos ver que o arquivo foo
está aberto:
$ strace cat foo 2| grep foo
execve("/bin/cat", ["cat", "foo"], [/* 44 vars */]) = 0
open("foo", O_RDONLY)
A primeira linha acima mostra que o programa /bin/cat
foi chamado e seus argumentos foram cat
e foo
(o primeiro argumento é sempre o próprio programa). Mais tarde, o argumento foo
foi aberto no modo somente leitura. Agora, compare isso com
$ strace ls foo 2| grep foo
execve("/bin/ls", ["ls", "foo"], [/* 44 vars */]) = 0
stat("foo", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
lstat("foo", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
write(1, "foo\n", 4foo
Aqui também, ls
tomou a si mesmo e foo
como argumentos. No entanto, não há open
call, o argumento não é tratado como entrada. Em vez disso, ls
chama a biblioteca stat
do sistema (que não é a mesma coisa que o comando stat
) para obter informações sobre o arquivo foo
.
Em resumo, se o comando que você estiver executando for ler sua entrada, você pode redirecioná-lo para ele, se não, você não pode.