web-dev-qa-db-fra.com

Comment échapper au caractère guillemet simple dans une commande ssh/remote bash?

Je construis un petit ensemble de scripts pour démarrer, arrêter et vérifier à distance le statut d'un processus. La stop de ces scripts doit rechercher un processus et le tuer. Donc je fais:

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

Le problème ici est que l'étape awk tokenization nécessite des guillemets simples et que ceux-ci se heurtent au guillemet simple utilisé pour exécuter la commande à distance via ssh. Comment échapper à ces guillemets simples?

19
SkyWalker

Utilisation

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

Ce n'est pas ssh ou awk manipulant les guillemets, c'est le shell (et ils sont nécessaires pour empêcher le shell de manipuler d'autres caractères spécialement, comme $). Leur imbrication n'est pas prise en charge (bien que d'autres structures, telles que $(), puissent être imbriquées même lorsqu'elles contiennent des guillemets), vous devrez donc échapper les guillemets simples séparément. Voici quelques méthodes:

$ 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!
12
Yann Vernier

Vous ne pouvez pas inclure une seule citation dans une chaîne contenant une seule citation. Cependant, cela n'a pas d'importance, car un seul argument peut avoir plusieurs segments entre guillemets (tant qu'il n'y a pas d'espaces non cités ou d'autres caractères auto-délimiteurs.)

Par exemple:

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

Cependant, cette ligne de commande est very clunky. Si possible, vous devriez utiliser l'utilitaire pkill , qui réduirait tout cela à ssh deploy@hera 'pkill -SIGKILL MapReduceNode'.

Sinon, vous pourriez faire toute la manipulation de chaîne en une seule invocation awk (non testée, mais je pense que cela fonctionnera):

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

(contrairement à l'original, cela tuerait toutes les tâches MapReduceNode plutôt que certaines premières. Si vous voulez vraiment le faire en une tâche, ajoutez ; exit à l'action awk.) 

8
rici

Il n’ya pas deux autres options que je ne vois pas mentionnées dans aucune des autres réponses. J'ai laissé le pipeline grep/grep/awk/head intact à des fins de démonstration, même si (comme indiqué dans la réponse de rici ), il pourrait être réduit à quelque chose comme:

awk -F ' ' '/MapReduceNod[e]/ {print $2; exit}'
  1. Utilisation de guillemets doubles pour toute la commande ssh:

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

    Notez que je peux maintenant utiliser des guillemets simples dans la commande, mais je dois échapper à d'autres éléments que je ne souhaite pas encore développer: \$() (que j'ai utilisé à la place des guillemets), les guillemets doubles \" et print \$2.

  2. Un ici-doc avec le délimiteur cité:

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

    Le -T empêche ssh de se plaindre de ne pas allouer de pseudo-terminal.

    Le ici doc avec le délimiteur cité est extra gentil car son contenu n'a pas besoin d'être modifié du tout en ce qui concerne les échappements, et il peut contenir des guillemets simples.

5
Benjamin W.

Un autre exemple consiste à traiter les guillemets simples ou doubles, car pour moi, par exemple, j'avais besoin d'interprétation et de remplacements variables. Si je veux créer une fonction pour afficher un msg sur le macOS de ma femme, je peux faire les choses suivantes:

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