Por que systemctl \ {restart, status} \ sshd \; trabalhos?

14

A saída do comando acima, quando transmitida pelo eco, é:

# echo systemctl\ {restart,status}\ sshd\;
systemctl restart sshd; systemctl status sshd;

Mesmo se eu colar a saída no terminal, o comando funcionará. Mas quando tento executar diretamente o comando, recebo:

# systemctl\ {restart,status}\ sshd\;
bash: systemctl restart sshd;: command not found...

Eu tenho duas perguntas..

  1. Como exatamente esse método de substituição e expansão é chamado? (Para que eu possa pesquisar e aprender mais sobre ele e como usá-lo corretamente).
  2. O que eu fiz de errado aqui? Por que isso não funciona?
Somenath Sinha
fonte

Respostas:

26

É uma forma de expansão do Brace feita no shell. A idéia de expansão-expansão está correta, mas a maneira como foi usada está incorreta aqui. Quando você pretendia fazer:

systemctl\ {restart,status}\ sshd\;

O shell interpreta systemctl restart sshd;como um comando longo e tenta executá-lo, e não conseguiu localizar um binário para executá-lo dessa maneira. Porque nesta fase, o shell tenta tokenizar os itens na linha de comando antes de criar o comando completo com argumentos - mas isso ainda não aconteceu.

Para esses valores de expansão conhecidos, você pode usar evale ainda estar seguro, mas certifique-se do que está tentando expandir com ele.

eval systemctl\ {restart,status}\ sshd\;

Mas eu prefiro usar um loop com for, em vez de tentar escrever um one-liner ou usar eval:

for action in restart status; do
    systemctl "$action" sshd
done
Inian
fonte
19

Isso é chamado de expansão entre chaves (como a tag indica).

O que eu fiz de errado aqui? Por que isso não funciona?

Considere os estágios envolvidos na leitura e execução de uma linha de comando no bash (por exemplo):

  1. lê uma linha
  2. analisa um comando possivelmente composto em comandos simples do componente
  3. faz várias expansões nos comandos simples (expansão de chaves, divisão de palavras, globbing etc.)
  4. depois executa os comandos simples (com outros estágios omitidos para maior clareza).

O que você está tentando fazer é afetar (2) de (3). A divisão com base em ;está no estágio (2), quando está analisando comandos compostos. Quando (3) está acontecendo para a expansão de chaves, já é tarde demais para tentar criar um comando composto.

muru
fonte
6

A primeira linha

echo systemctl\ {restart,status}\ sshd\;

expandir como 3 token

  • eco
  • systemctl restart sshd;
  • systemctl status sshd;

depois eco eco os dois últimos token, e parece OK.

da mesma forma a segunda linha

systemctl\ {restart,status}\ sshd\;

expande como 2 tokens

  • systemctl restart sshd;
  • systemctl status sshd;

e o bash tenta procurar um executável systemctl restart sshd;que não foi possível encontrar.

Você pode querer começar sua jornada no lado escuro usando eval systemctl\ {restart,status}\ sshd\;cuidado com o inesperado.

Archemar
fonte
então, a solução seria dividir palavras, certo? Como isso pode ser feito?
Somenath Sinha 27/03