Fazer eco de um comando cauda produz uma saída inesperada?


8

Este comando, quando executado sozinho, produz o resultado esperado (a última linha do crontab):

tail -n 1 /etc/crontab

No entanto, quando eu o executo como parte de um comando de eco para enviar o resultado para um arquivo, ele adiciona um resumo de todos os arquivos no diretório ativo, além do resultado esperado:

sudo bash -c 'echo $(tail -n 1 /etc/crontab) > /path/to/file'

Por que esse comando produziu os dados extras?



3
O que está echofazendo por você aqui? Considere tambémtail -n 1 /etc/crontab | sudo tee /path/to/file >/dev/null
ctrl-alt-delor 16/04/19

Respostas:


22

Sua linha do crontab possui um ou mais asteriscos *, indicando "a qualquer momento". Quando essa linha é substituída na substituição de comando, o resultado é algo como

echo * * * * * cmd > /path/to/file

Enquanto a maioria das expansões adicionais não é aplicada à saída da substituição de comando, a expansão do nome do caminho é (como é a divisão do campo) :

Os resultados da substituição de comando não devem ser processados ​​para expansão adicional de til, expansão de parâmetro, substituição de comando ou expansão aritmética. Se uma substituição de comando ocorrer entre aspas duplas, a divisão de campo e a expansão do nome do caminho não devem ser executadas nos resultados da substituição.

A expansão do nome do caminho é o que se transforma *.txtem uma lista de nomes de arquivos correspondentes (globbing), onde *corresponde a tudo. O resultado final é que você obtém todos os nomes de arquivos (não ocultos) no diretório de trabalho listados para todos os *itens da sua linha crontab.


Você pode corrigir isso citando a expansão, se o código publicado for um representante de um comando mais complexo:

sudo bash -c 'echo "$(tail -n 1 /etc/crontab)" > /path/to/file'

mas, mais diretamente, apenas perco echocompletamente:

sudo bash -c 'tail -n 1 /etc/crontab > /path/to/file'

Isso deve fazer o que você deseja e também é mais simples (a única outra diferença material é que esta versão omitirá a divisão de campos que, de outra forma, teria ocorrido, para que a execução de espaços não seja recolhida).


5
Como o / etc / crontab é quase sempre legível por todo o mundo, todo o truque "bash -c" é realmente desnecessário: tail -n -1 /etc/crontab | sudo tee /path/to/fileé o idioma que eu achei menos propenso a erros ao redirecionar a saída para arquivos que exigem privilégios de superusuário.
Baixo

5

Vamos considerar um diretório com esses arquivos:

$ ls
crontab  file1  file2  file3
$ cat crontab
f*

Agora, vamos executar o comando tail:

$ tail -n 1 crontab
f*

A descrição acima é a última linha de crontabe é isso que esperamos. Contudo:

$ echo $(tail -n 1 crontab)
file1 file2 file3

Aspas duplas eliminam esse problema:

$ echo "$(tail -n 1 crontab)"
f*

Sem as aspas duplas, o resultado da substituição do comando é expandido pelo shell. Uma das expansões é a expansão do nome do caminho . No caso acima, isso significa que f*é expandido para corresponder a todos os nomes de arquivos que começam com f.

A menos que você queira explicitamente expansões de shell, coloque todas as variáveis ​​de shell e / ou substituições de comandos entre aspas duplas.


4

O mecanismo do shell globing será expandido *para o arquivo local.

a linha crontab provavelmente terá um *espaço reservado para qualquer.

por exemplo, esta linha no crontab é executada às 7h07 no domingo, a primeira estrela significa qualquer dia, a segunda a cada mês.

47  7 * * 0 /run/on/sunday

então você taile emita

echo 47  7 * * 0 /run/on/sunday

que será expandido *para o arquivo local.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.