Tenho um arquivo chamado fileWithOneCommand.txt
com apenas um comando como segue
ps -aux|head -n 5
então escrevo um script de shell de teste chamado 'test5.sh' com o seguinte conteúdo:
file=/home/somepath/fileWithOneCommand.txt
$file;
echo see;
cat $file;
echo see2;
$(cat $file);
echo see3;
mas não consigo entender o resultado, o resultado é o seguinte:
$ ./test5.sh
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 168584 10308 ? Ss Feb19 0:49 /sbin/init splash
root 2 0.0 0.0 0 0 ? S Feb19 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? S Feb19 0:00 [pool_workqueue_release]
root 4 0.0 0.0 0 0 ? I< Feb19 0:00 [kworker/R-rcu_g]
see
ps -aux|head -n 5
see2
error: user name does not exist
Usage:
ps [options]
Try 'ps --help <simple|list|output|threads|misc|all>'
or 'ps --help <s|l|o|t|m|a>'
for additional help text.
For more details see ps(1).
see3
$file deve mostrar o conteúdo da variável file, então deve ser a saída,
ps -aux|head -n 5
mas por que a saída é o resultado da execução de ps -aux|head -n 5, e não apenas mostrar ps -aux|head -n 5?cat $file; return ps -aux|head -n 5, mas por que
$(cat $file);
retornar erro "erro: nome de usuário não existe"?
Quando pesquisei sobre substituição de comando no Google, ele disse "a saída de um comando substitui o próprio comando. O Shell opera a expansão executando um comando e, em seguida, substituindo a substituição do comando pela saída padrão do comando".
então para
$(cat $file);
dentro do colchete, cat $file retorna ps -aux|head -n 5 então por que $(cat $file); não retorna o resultado da execução de ps -aux|head -n 5 mas retorna um erro "erro: nome de usuário não existe"?
O resultado de expansões de shell (seja $() ou $variable ou mesmo substituição de comando backtick) não passa por análise de entrada de shell "completa" – apenas divisão de palavras (e eu acho que expansão de curinga). Neste exemplo específico, se o resultado contiver um
|
, ele não será analisado como o operador pipe – ele permanecerá um literal "|".Então, em vez de dois comandos
ps -aux
ehead -n 5
, todo o resultado da expansãops -aux|head -n 5
permanece um único comando com 3 argumentos:"ps"
"-aux|head"
"-n"
"5"
.O Linux
ps
tenta combinar dois estilos de linha de comando muitops
diferentes (BSD e SysV), e a mesma opção pode significar duas ou três coisas diferentes dependendo de qual 'modo' adivinha. Por exemplo, o BSD tem-u
, mas o SysV tem-u <username>
which faz uma coisa diferente.Neste caso, ele primeiro tenta interpretar o primeiro argumento como opções no estilo BSD
-a
-u
-x
-|
…, mas como a opção-|
não existe, o programa muda para o estilo SysV, onde-u
recebe um parâmetro.O restante
x|head
, portanto, se torna o parâmetro "nome de usuário" para a-u
opção SysV e, como nenhuma conta de usuário desse tipo existe no seu sistema, você recebe a mensagem de erro.Para forçar uma string a ser analisada por completo, você precisa
eval
dela. Por exemplo,eval "$mycmd"
oreval "$(cat $myfile)"
– embora o último seja melhor escrito como. $myfile
orsource $myfile
.A
~/bin/args
ferramenta (variantes bash e C):