Não existem "regras" como tais. Alguns programas recebem entrada do STDIN e outros não. Se um programa pode receber informações do STDIN, ele pode ser canalizado para, se não, não pode.
Normalmente, você pode dizer se um programa irá receber informações ou não, pensando no que faz. Se o trabalho do programa é de alguma forma manipular os conteúdos de um arquivo (por exemplo grep, sed, awketc.), que normalmente leva a entrada de STDIN. Se seu trabalho é manipular o arquivo em si (por exemplo mv, rm, cp) ou um processo (por exemplo kill, lsof) ou às informações de retorno 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, mvnão tem entrada como tal. O que foi dado são dois argumentos. Ele não sabe nem se importa com o que está em nenhum dos arquivos, apenas sabe que esses são seus argumentos e deve manipulá-los.
Por outro lado
sed -e 's/foo/bar/' < file
--- -- ------------ ----
| | | |-> input
| | |------------> argument
| |--------------------> option/flag/switch
|------------------------> command
Aqui, sedfoi dada entrada, bem como um argumento. Uma vez que recebe entrada, ela pode ser lida no STDIN e pode ser canalizada para.
Fica mais complicado quando um argumento pode ser a entrada. Por exemplo
cat file
Aqui fileestá o argumento que foi dado cat. Para ser mais preciso, o nome do arquivo fileé o argumento. No entanto, como caté um programa que manipula o conteúdo dos arquivos, sua entrada é o que estiver dentro file.
Isso pode ser ilustrado usando straceum programa que rastreia as chamadas do sistema feitas por processos. Se cat foorodarmos strace, podemos ver que o arquivo fooé 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/catfoi chamado e seus argumentos foram cate foo(o primeiro argumento é sempre o próprio programa). Posteriormente, o argumento foofoi 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, lstomou-se e foocomo argumentos. No entanto, não há openchamada, o argumento não é tratado como entrada. Em vez disso, lschama a statbiblioteca do sistema (que não é a mesma coisa que o statcomando) para obter informações sobre o arquivo foo.
Em resumo, se o comando que você está executando ler sua entrada, você poderá canalizar para ele; se não, não poderá.
pgrep,pkillekillallcomandos.