¿Por qué systemctl \ {restart, status} \ sshd \; ¿trabajo?

14

La salida del comando anterior cuando se pasa por echo es:

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

Incluso si pego la salida en la terminal, el comando funciona. Pero cuando intento ejecutar directamente el comando, obtengo:

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

Tengo dos preguntas..

  1. ¿Cómo se llama exactamente este método de sustitución y expansión? (Para que pueda investigarlo y aprender más sobre él y cómo usarlo correctamente).
  2. ¿Qué hice mal aquí? ¿Por qué no funciona?
Somenath Sinha
fuente

Respuestas:

26

Es una forma de expansión de Brace realizada en el caparazón. La idea de expansión de llaves es correcta, pero la forma en que se usó es incorrecta aquí. Cuando querías hacer:

systemctl\ {restart,status}\ sshd\;

El shell interpreta systemctl restart sshd;como un comando largo e intenta ejecutarlo, y no pudo encontrar un binario para ejecutarlo de esa manera. Porque en esta etapa, el shell intenta simular los elementos en la línea de comando antes de construir el comando completo con argumentos, pero aún no ha sucedido.

Para tales valores de expansión conocidos, podría usar evaly estar seguro, pero asegúrese de lo que está tratando de expandir con él.

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

Pero prefiero usar un bucle con for, en lugar de intentar escribir una línea o usar eval:

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

Esto se llama expansión de llaves (como lo indica la etiqueta).

¿Qué hice mal aquí? ¿Por qué no funciona?

Considere las etapas involucradas en la lectura y ejecución de una línea de comando en bash (por ejemplo):

  1. lee una línea
  2. analiza un comando posiblemente compuesto en comandos simples componentes
  3. realiza varias expansiones en los comandos simples (expansión de llaves, división de palabras, globbing, etc.)
  4. luego ejecuta los comandos simples (con otras etapas omitidas para mayor claridad).

Lo que estás tratando de hacer es afectar (2) de (3). La división basada en ;está en la etapa (2), cuando analiza los comandos compuestos. Para cuando (3) está sucediendo para la expansión de llaves, ya es demasiado tarde para intentar crear un comando compuesto.

muru
fuente
6

La primera línea

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

expandir como 3 tokens

  • eco
  • systemctl reiniciar sshd;
  • systemctl status sshd;

luego echo echo los dos últimos tokens, y se ve bien.

igualmente la segunda línea

systemctl\ {restart,status}\ sshd\;

se expande como 2 tokens

  • systemctl reiniciar sshd;
  • systemctl status sshd;

y bash intenta buscar un ejecutable systemctl restart sshd;que no pudo encontrar.

Es posible que desee comenzar su viaje en el lado oscuro con eval systemctl\ {restart,status}\ sshd\;cuidado con lo inesperado.

Archemar
fuente
entonces, la solución sería dividir palabras, ¿verdad? ¿Cómo se puede hacer esto?
Somenath Sinha