web-dev-qa-db-fra.com

Comment passer des commandes Shell complexes sur SSH à exécuter à distance? Mine jeter des erreurs de syntaxe ou se faire interpréter localement!

J'ai une commande comme celle-ci qui me dit si un système a un disque qui est plein (> = 70%):

if [[ -n df -PTh|column -t|awk '{print $6 $7}'|awk -F"%" '{printf "%-9s %-5s\n",$1,$2}'|grep -v -e "Use" -e "Mounted"|awk '$1>70{printf "%-9s %-5s\n",$1,$2}' ]]; then echo "not present"; else echo ">70 is present"; fi

Je souhaite exécuter la commande ci-dessus sur un serveur distant utilisant SSH. Quelque chose comme:

ssh remoteserver "if [[ -n df -PTh|column -t|awk '{print $6 $7}'|awk -F"%" '{printf "%-9s %-5s\n",$1,$2}'|grep -v -e "Use" -e "Mounted"|awk '$1>70{printf "%-9s %-5s\n",$1,$2}' ]]; then echo "not present"; else echo ">70 is present"; fi"

Mais quand j'ai essayé ça, j'ai eu l'erreur suivante:

Host: remoteserver bash: -c: line 0: syntax error in conditional expression bash: -c: line 0: syntax error near /home'
bash: -c: line 0:if [[ -n 92 /home'
3
user275225

Tout d’abord, je réduirais ce crime de guerre d’une déclaration awk/grep/awk/grep/awk/grep/etc à:

df | awk '$5~/([7-9]|10)[0-9]/'

Il fait tout ce dont vous avez besoin pour vérifier la sortie. Vous pouvez ajouter une clause {print ...} à la déclaration awk si vous aviez besoin d'une jolie sortie, mais sachant que vous êtes simplement en train de vérifier si il y a une sortie, soyons raisonnables à ce sujet.

Nous pouvons également raccourcir le if/else. J'ai également corrigé la direction - la tienne était inversée. La commande entière ressemble maintenant à:

[[ -n $(df | awk '$5~/([7-9]|10)[0-9]/') ]] && echo 'ACHTUNG!' || echo 'No >=70s'

Je pense que vous conviendrez que c'est juste légèrement plus édifiant.

Maintenant, vous pouvez probablement y échapper manuellement et l’envelopper dans un bash -c "...", mais où est le plaisir? Au lieu de cela, sauvegardons la commande dans un fichier local (par exemple, commands.txt), vous pouvez l'envoyer au serveur comme ceci:

ssh user@Host $(<commands.txt)

Et vous pouvez le laisser là. Vous pouvez en fait y insérer une version de travail de votre commande d'origine et l'envoyer. Cette chose est assez robuste ... Mais nous ne voulons pas faire ça ... Pas quand nous pouvons être plus intelligents (et tricheurs) avec la commande et supprimer les crochets if (qui sont la cause du problème qui échappe ).

Nous utilisons actuellement df à distance et le traitons à distance. Nous n'avons pas besoin de faire ça. Nous pourrions laisser ssh exécuter df puis gérer la sortie localement. Cela résout instantanément le problème qui nous échappe mais nous sommes actuellement bloqués dans la logique [[ entre crochets ]], ce qui rendrait la réécriture un peu moche:

[[ -n $(ssh user@Host df | awk '$5~/([7-9]|10)[0-9]/') ]] && .......

Beurk.
Nous sommes meilleurs que cela.
Contrairement aux singes et aux grands singes qui nous ont précédés, nous avons des codes de sortie.

Lorsque quelque chose se termine, il peut renvoyer un code. Ces codes signifient diverses choses mais en général, 0 signifie "j'ai fait exactement ce pour quoi je étais destiné" et tout ce qui est plus élevé signifie "j'ai mal fait, Bawss".

Les crochets conditionnels tels que && et || se tournent vers le code de sortie qui les alimente pour décider de leur exécution ou non. Dans notre cas, cela signifie que si nous disons à awk de quitter de manière non nulle, nous pouvons contrôler le flux de code:

ssh user@Host df | awk '$5~/([7-9]|10)[0-9]/ {exit 1}' && echo 'No >=70s' || echo 'ACHTUNG!'

Cela signifie également qu'il sortira dès qu'il détectera la première valeur> = 70. Si vous aviez des millions de lecteurs, cela pourrait vous faire économiser secondes par rapport aux autres scripts de grandes marques. Alors oui, juste pour réaffirmer ce qui se passe dans cette version finale:

  1. Nous nous connectons au serveur et exécutons df à distance
  2. La sortie est redirigée vers une instance locale de awk
  3. awk cherche à savoir si la cinquième colonne correspond à une expression régulière correspondant à 70-100
  4. Si c'est le cas, il quitte le code 1 et le code || s'exécute (il correspond à un lecteur utilisé à plus de 70%)
  5. Si ce n'est pas le cas, il quitte le code 0 et le code && s'exécute.

Dans les révisions précédentes, j’avais également un contrôle NR>1 dans les instructions awk, mais étant donné que nous vérifions explicitement la valeur de la cinquième colonne (et qu’il doit y avoir un nombre à travailler), nous pouvons omettre en toute sécurité. ça aussi.

8
Oli