bash ssh quoting

¿Cómo escapar del carácter de comillas simples en un comando ssh/remote bash?



quoting (5)

Estoy creando un pequeño conjunto de scripts para iniciar, detener y verificar de forma remota el estado de un proceso. La stop de estos scripts debe buscar un proceso y matarlo. Por eso hago:

ssh deploy@hera ''kill -9 `ps -ef | grep MapReduceNode | grep -v "grep" | awk -F " " ''{print $2}'' | head -n 1`''

El problema aquí es que el paso de tokenización awk necesita comillas simples y estas chocan con las comillas simples utilizadas para ejecutar el comando remoto a través de ssh. ¿Cómo se pueden escapar estas comillas simples?


Esto no es ssh o awk manejando las comillas, es el shell (y son necesarios para evitar que el shell maneje otros caracteres especialmente, como $ ). Anidarlos no es compatible (aunque otras estructuras, como $() pueden anidar incluso si contienen comillas), por lo que tendrá que escapar de las comillas simples por separado. Aquí hay un par de métodos:

$ echo ''Don''"''"''t mess with this apostrophe!'' Don''t mess with this apostrophe! $ echo ''Don''/'''t mess with this apostrophe!'' Don''t mess with this apostrophe!


Hay dos opciones más que no veo mencionadas en ninguna de las otras respuestas. He dejado la tubería grep / grep / awk / head intacta para fines de demostración, aunque (como se alude en la respuesta de rici ) podría reducirse a algo como

awk -F '' '' ''/MapReduceNod[e]/ {print $2; exit}''

  1. Usando comillas dobles para todo el comando ssh:

    ssh deploy@hera "kill -9 /$(ps -ef | grep MapReduceNode | grep -v /"grep/" | awk -F '' '' ''{print /$2}'' | head -n 1)"

    Tenga en cuenta que puedo usar comillas simples en el comando ahora, pero tengo que escapar de otras cosas que todavía no quiero expandir: /$() (que he usado en lugar de comillas invertidas), comillas dobles /" e print /$2 .

  2. Un aquí-doc con delimitador entre comillas:

    ssh -T deploy@hera <<''EOF'' kill -9 $(ps -ef | grep MapReduceNode | grep -v ''grep'' | awk -F '' '' ''{print $2}'' | head -n 1) EOF

    La -T evita que ssh se queje de no asignar un pseudo-terminal.

    El documento aquí con delimitador entre comillas es muy bueno porque su contenido no tiene que ser modificado en absoluto con respecto a las cosas que se escapan, y puede contener comillas simples.


No puede incluir una sola cita en una cadena entre comillas simples. Sin embargo, eso no importa porque un solo argumento puede tener más de un segmento entre comillas (siempre que no haya espacios en blanco sin comillas u otros caracteres autodelimitados).

Por ejemplo:

ssh deploy@hera ''kill -9 `ps -ef | grep MapReduceNode | grep -v "grep" | awk -F " " ''/'''{print $2}''/'" | head -n 1`"

Sin embargo, esa línea de comando es muy torpe. Si es posible, debería usar la utilidad pkill , que reduciría todo eso a ssh deploy@hera ''pkill -SIGKILL MapReduceNode'' .

De lo contrario, podría realizar toda la manipulación de cadenas en una sola invocación awk (sin probar, pero creo que funcionará):

ssh deploy@hera ''ps -ef | awk "/[M]apReduceNode/{system(/"kill -9 /"$2)}"''

(a diferencia del original, esto eliminará todas las tareas de MapReduceNode en lugar de las primeras arbitrarias. Si realmente desea realizar solo una tarea, agregue ; exit a la acción awk).


Otro ejemplo es tratar con comillas simples o dobles porque para mí, por ejemplo, necesitaba interpretación y reemplazos de variables. Si quiero hacer una función para mostrar un msg al macOS de mi mujer, puedo hacer lo siguiente:

ssh womanLptp "osascript -e ''tell app /"System Events/" to display dialog /"${1}/"''"


Utilizar

ssh deploy@hera ''kill -9 `ps -ef | grep MapReduceNode | grep -v "grep" | awk -F " " ''"''"''{print $2}''"''"'' | head -n 1`''