web-dev-qa-db-fra.com

Comment SSH peut-il fonctionner avec une condition if?

J'ai une instruction if pour calculer des fichiers et supprimer tous sauf les trois derniers fichiers. Mais je veux exécuter cette commande à distance. Comment puis-je combiner ssh avec une condition if?

J'ai essayé cela mais sans succès.

#!/bin/bash

ssh -t  [email protected] "cd /var/www/test.com/backup ;

if [ $(ls  | wc -l) -lt 3  ]
then
    echo "Less"
else [ $(ls -t *.tgz|awk 'NR >3'|xargs rm -f) ]
    echo "deleted"
fi"

L'erreur que j'ai eu:

ls: impossible d'accéder à * .tgz: aucun fichier ou répertoire de ce type

8
Janith

NOTE: il y a en fait deux couches à la question ici. La première est "Je veux exécuter une tâche non triviale sur un serveur distant accessible via SSH". La seconde est "J'essaie de passer un complexe chaîne à une commande, et l'argument finit par être différent de celui que je voulais. "Je réponds à la question de bas niveau sans indiquer si l'approche utilisée est" correcte "(commode, non sujette aux erreurs, sécurisée, etc.) comme indiqué dans les autres réponses et commentaires, ce n’est peut-être pas le cas.

Votre ligne de commande est généralement correcte. il suffit de changer un peu la citation.

Le principal problème est que les chaînes entre guillemets sont développées par votre shell local. Les parties $(...) seront donc évaluées sur votre système local. Pour les transférer au système distant, vous devez inclure le script entre guillemets simples.

Vous avez également des guillemets incorporés. Dans votre script d'origine, il y a les arguments pour les deux echos; si vous changez la citation externe en guillemets simples, ce sera le script awk. Cela a pour effet d’omettre les guillemets, ce qui ne gêne pas le echos, mais gâchera le script awk, car le signe supérieur à deviendra une redirection de sortie. Ainsi, après avoir modifié les guillemets extérieurs en guillemets simples, modifiez ceux-ci en guillemets doubles.

Ceci est votre script avec la citation corrigée. Le script peut avoir d'autres problèmes, je viens de corriger la syntaxe.

#!/bin/bash

ssh -t  [email protected] 'cd /var/www/test.com/backup ;

if [ $(ls  | wc -l) -lt 3  ]
then
  echo "Less"
else [ $(ls -t *.tgz|awk "NR >3"|xargs rm -f) ]
  echo "deleted"
fi'
3
pt314

Oui, vous pouvez exécuter des scripts complexes via sshname__

#!/bin/bash -e

ssh_cmd="$(cat <<-EOF
    cd /var/www/test.com/backup;

    if [ \$(ls  | wc -l) -lt 3  ]; then
        echo "less"
    Elif [ \$(ls -t *.tgz|awk 'NR >3'|xargs rm -f) ]; then
        echo "deleted"
    else
        echo "something else"
    fi
EOF
)"

ssh -t [email protected] "$ssh_cmd"

Cet exemple utilise un bash ici document pour générer la chaîne de commande. Dans tous les cas, le fait de passer des scripts via ssh est sujet aux erreurs, car il est difficile de citer et échapper des variables (faites attention à la barre oblique inverse avant les commandes). Si le script devient trop complexe, il est préférable de le copier via scpname__, puis de l'exécuter sur l'hôte cible.

Je n'ai pas essayé de corriger votre script , mais voici un exemple montrant comment le comptage et la suppression sur un hôte distant peuvent fonctionner:

#!/bin/bash -e

tmp_dir="$(mktemp -d)"

ssh_cmd="$(cat <<-EOF
    cd "$tmp_dir"

    cnt_tgz=(\$(find . -type f -name "*.tgz"))
    if [[ \${#cnt_tgz[@]} -lt 3 ]]; then
        echo "less"
    else
        rm "\${cnt_tgz[@]}"
        echo "deleted"
    fi
EOF
)"

touch "$tmp_dir/1.tgz"
ssh -t localhost "$ssh_cmd"
touch "$tmp_dir/2.tgz" "$tmp_dir/3.tgz"
ssh -t localhost "$ssh_cmd"

Le ls -t *.tgz ne fonctionnera pas, car le globbing ne se produit que sur le système local. Utiliser également lspour compter les fichiers n'est pas une bonne idée, car il renvoie également des entrées telles que ., .. et des répertoires.

10
Simon Sudler

Je pense que cette citation compliquée est une preuve suffisante pour ne pas l'utiliser, mais utiliser un script à la place. Si vous souhaitez éviter plusieurs connexions sshname__, dirigez le script vers l'autre hôte et laissez-le s'exécuter en une seule commande:

Fichier local, dites myscript.sh:

cd /var/www/test.com/backup;

if [ $(ls  | wc -l) -lt 3  ]; then
    echo "less"
Elif [ $(ls -t *.tgz|awk 'NR >3'|xargs rm -f) ]; then
    echo "deleted"
else
    echo "something else"
fi

Ensuite:

cat myscript.sh | \
    ssh -t [email protected] \
    "cat - > /tmp/ms.sh && sh /tmp/ms.sh && rm /tmp/ms.sh"

Ou (en évitant tilisation inutile du chat ):

ssh -t [email protected] \
    "cat - > /tmp/ms.sh && sh /tmp/ms.sh && rm /tmp/ms.sh" \
    < myscript.sh

Cela dirige le script local myscript.sh vers le côté distant où il est redirigé vers un fichier (temporaire) /tmp/ms.sh, exécuté et finalement supprimé.

Remarque: je n'ai pas vérifié les erreurs dans le script d'origine, mais je voulais simplement montrer l'idée. Aucune citation sujet aux erreurs n'est nécessaire et toutes les commandes du script sont exécutées du côté distant.

4
PerlDuck

Je préférerais placer le script sur l'instance distante et simplement l'exécuter via ssh, mais voici ma suggestion: comment cela pourrait-il être réalisé comme vous le souhaitez:

#!/bin/bash

Host='[email protected]'
REMOTE_PATH='/var/www/test.com/backup'

COMMAND1="ssh \"$Host\" 'ls \"$REMOTE_PATH\" | wc -l'"
COMMAND2="ssh \"$Host\" 'ls -t \"$REMOTE_PATH\"/*.tgz'"
COMMAND3="xargs ssh \"$Host\" rm -rf"

if [[ $(eval "$COMMAND1") -le 3 ]]
then
    echo "Less"
else
    eval "$COMMAND2" | awk 'NR > 3' | eval "$COMMAND3" && echo "Deleted"
fi

Remarques:

  • L'expression conditionnelle -lt est remplacée par -le.
  • eval - construit une commande en concaténant des arguments.
  • Je ne sais pas si nous avons vraiment besoin de ces citations supplémentaires \" dans l'expression $COMMAND{1..3}, mais j'ai décidé de les ajouter.
3
pa4080