web-dev-qa-db-fra.com

Capture de la sortie SSH en tant que variable dans le script bash

J'ai eu du mal avec ce problème lors de l'écriture d'un script bash. Fondamentalement, je veux mesurer le temps d'un programme sur un serveur distant, donc j'utilise la commande: /usr/bin/time -f %e sh -c "my command > /dev/null 2>&1" pour exécuter le programme. Cependant, il semble que je ne puisse pas du tout capturer la sortie de ma commande (SSH) dans une variable. En fait, le résultat (temps) continue d'être imprimé sur stdout.

Le code complet est:

respond=$(ssh ${fromNode} /usr/bin/time "-f" "%e" "'sh' '-c' 'virsh migrate --live ${VM} qemu+ssh://${toNode}/system --verbose > /dev/null 2>&1'")

La valeur de respond est juste vide, bien que l'heure soit imprimée sur la sortie standard.

17
Andy Dang

La commande "time" imprime le résultat sur stderr, pas sur stdout. Il n'est donc pas canalisé dans votre variable.

Vous devez rediriger stderr vers stdout pour obtenir ce que vous voulez:

 result=$(ssh Host time "command" 2>&1)

Et votre code complet peut ressembler à ceci:

 respond=$(ssh ${fromNode} /usr/bin/time "-f" "%e" "'sh' '-c' 'virsh migrate --live ${VM} qemu+ssh://${toNode}/system > /dev/null 2>&1'" 2>&1)
37
Rogach

Essayez d'échanger l'ordre de vos redirections (vers 2>&1 >/dev/null). Votre code actuel envoie à la fois stdout et stderr à/dev/null (donc je suis un peu curieux de savoir pourquoi n'importe quoi est imprimé du tout).

Pourquoi est-ce nécessaire? La syntaxe 2>&1 signifie 'stdout en double (descripteur 1) comme stderr (descripteur 2)'; en effet, stderr est transformé en une copie de la sortie standard actuelle. Si vous mettez >/dev/null d'abord, puis stdout est d'abord redirigé vers/dev/null, puis stderr est pointé vers la sortie standard actuelle, c'est-à-dire/dev/null.

Mais si vous mettez >/dev/null deuxièmement, stderr deviendra d'abord une copie de la sortie standard actuelle (le flux de sortie normal), avant que la sortie standard ne soit redirigée. Ainsi, la commande stderr s'imprime sur le tty (ou l'interpréteur) comme si elle provenait de stdout, tandis que stdout est désactivée. C'est le comportement que vous souhaitez.

De man bash:

Notez que l'ordre des redirections est significatif. Par exemple, la commande

ls > dirlist 2>&1

dirige à la fois la sortie standard et l'erreur standard vers la liste de fichiers, tandis que la commande

ls 2>&1 > dirlist

dirige uniquement la sortie standard vers le fichier dirlist, car l'erreur standard a été dupliquée en tant que sortie standard avant que la sortie standard ne soit redirigée vers dirlist.

2
nneonneo