2012-12-03 4 views
3

Je ne connais pas encore les scripts shell, mon script semble correct, mais c'est le flux que j'ai un problème de contrôle. Quelqu'un pourrait-il signaler quelle erreur idiote j'ai faite s'il vous plaît.Problème de contrôle du flux de script

#! /bin/sh 

echo "Are you sure youx want to delete $1? Answer y or n" 
read ans 
echo $ans 
if $ans = "y"|"Y" 
then 
    mv $1 /home/parallels/dustbin 
    echo "File $1 has been deleted" 
else echo "File $1 has not been deleted" 
fi 

Répondre

1

Faites votre si la condition comme ceci:

if [ "$ans" = "y" -o "$ans" = "Y" ] 
+0

Merci pour la réponse rapide et utile! –

+1

Vous êtes les bienvenus ... Si la solution a fonctionné pour vous, acceptez la réponse. Si plusieurs réponses vous conviennent, acceptez celle qui correspond le mieux à votre problème ... – Guru

0

Vous pouvez également convertir la réponse de l'utilisateur pour les deux cas, et il suffit de vérifier pour le cas respectif comme

read ans 
ans=${ans,,} # make 'ans' lowercase, or use ${ans^^} for making it uppercase 
if [ "$ans" = "y" ] 
then 
    .... 
fi 
+0

Cette méthode de conversion en minuscule ne fonctionne que dans bash. Le script de l'OP exécute '/ bin/sh' - nous ne savons pas si bash est également disponible, mais même si c'est le cas, votre réponse devrait probablement spécifier bash comme exigence, puisque bash utilise le comportement POSIX lorsqu'il est appelé' sh'. – ghoti

1

Il y a quelques les choses ne vont pas avec votre script. Certains sont sérieux, d'autres moins.

Tout d'abord, les problèmes graves. Comme le suggère le gourou, vous devez utiliser des crochets pour entourer la condition if. En effet, if ne teste que la sortie d'une condition, il n'effectue pas de comparaison de chaînes réelles. Traditionnellement, un programme appelé /bin/test, également appelé /bin/[, prenait soin de cela. Ces jours-ci, cette fonctionnalité est intégrée au shell, mais /bin/sh se comporte toujours comme s'il s'agissait d'un programme distinct.

En fait, vous pouvez faire des choses intéressantes avec if lorsque vous ne pas utiliser des crochets pour votre condition. Par exemple, if grep -q 'RE' /path/to/file; then est assez commun. La commande grep -q ne génère aucune sortie, mais renvoie simplement un "succès" ou un "échec" détecté par if.

Le deuxième problème sérieux est que vous faites écho à un état qui peut ou peut ne pas être vrai. J'appelle cela un sérieux problème parce que ... eh bien, les messages de journal ne devraient tout simplement pas faire de fausses déclarations. Si les autorisations sont incorrectes pour le fichier $1 ou si le nom de fichier contient un espace, votre commande mv échouera, mais le message indiquera que ce n'est pas le cas. Plus à ce sujet plus tard.

Ensuite, les problèmes les moins graves.

Ce sont principalement des choses de style et d'optimisation.

Tout d'abord, read sur la plupart des plates-formes inclut une option -p qui vous permet de spécifier une invite. Utilisez ceci, et vous n'avez pas besoin d'inclure une commande echo. Deuxièmement, l'indentation rend difficile la visualisation de la structure de la construction if. Ce n'est pas un énorme problème dans un programme aussi petit, mais au fur et à mesure que vous grandissez, vous voulez VRAIMENT suivre des normes cohérentes. Troisièmement, vous pouvez probablement obtenir plus de flexibilité dans les questions à choix multiple comme ceci si vous utilisez les instructions case au lieu de if.

Après tout cela, voici comment j'écrire ce script:

#!/bin/sh 

if [ "$1" = "-y" ]; then 
    ans=y 
    shift 
elif [ -t 0 ]; then 
    read -p "Are you sure you want to delete '$1' (y/N) ? " ans 
fi 

case "$ans" in 
    Y*|y*) 
    retval=0 
    if [ -z "$1" ]; then 
     retval=64 
     echo "ERROR: you didn't specify a filename." >&2 
    if [ ! -f "$1" ]; then 
     retval=66 
     echo "ERROR: file '$1' not found!" >&2 
    elif mv "$1" /home/parallels/dustbin/; then 
     echo "File '$1' has been deleted" >&2 
    else 
     retval=$? 
     echo "ERROR: file '$1' could not be deleted!" >&2 
    fi 
    ;; 
    *) 
    echo "ABORT: file '$1' has not been deleted" >&2 
    retval=4 
    ;; 
esac 

exit $retval 

En dehors de ce qui est mentionné ci-dessus, voici quelques choses dans ce bout de code:

  • [ "$1" = "-y" ] - si l'utilisateur spécifie une option -y, puis nous nous comportons comme si la réponse à la question était "oui".
  • [ -t 0 ] - ceci teste si nous sommes sur un terminal interactif. Si nous sommes, alors il est logique de poser des questions avec read.
  • Y*|y*) - dans une instruction case, ceci correspond à toute chaîne commençant par un "y" majuscule ou minuscule. Les réponses affirmatives valides seraient donc "Y", "oui", "jaune", etc.
  • [ ! -f "$1" ] - ceci teste si le fichier existe. Vous pouvez man test ou man sh pour voir les différents tests disponibles dans shell. (-f peut ne pas être le plus approprié pour vous.)
  • >&2 - à la fin d'une ligne, envoie sa sortie à "erreur standard" au lieu de "sortie standard". Cela change la façon dont la sortie sera traitée par les canaux, cron, etc. Les erreurs et les données du journal sont souvent envoyées à stderr, de sorte que stdout peut être dédié à la sortie réelle d'un programme.
  • mv "$1" ... - Le nom de fichier est entre guillemets. Cela vous protège au cas où le nom de fichier contient des caractères spéciaux comme des espaces.
  • $retval - les valeurs pour cela provenaient d'une meilleure estimation de l'article le plus proche en man sysexits.
  • retval=$? - il s'agit du statut de sortie de la dernière commande exécutée. Dans ce cas, cela signifie que nous attribuons l'état de sortie mv à la variable $retval, de sorte que si mv a échoué, le script entier indique la raison de l'échec, en ce qui concerne mv.
+0

+1 phew .. cette réponse est un tel exercice d'apprentissage –

+0

seule question que je ai est s'il serait nécessaire de renvoyer également des codes d'erreur du script lorsque, par exemple, le 'mv' échoue (ce qui est actuellement caché par le' echo ERROR ..' that would return ok) –

+0

@GermanGarcia - oui, ce pourrait être une bonne idée, surtout si le script est conçu de sorte qu'il peut être enveloppé par d'autres scripts. J'ai mis à jour la réponse pour inclure plus "d'apprentissage". :-) – ghoti

0

Ci-dessous le code parfait avec la gestion des erreurs inclus

#!/bin/sh 

echo "Are you sure you want to delete $1? Answer y or n" 
read ans 
echo $ans 

if [ $ans == "y" ] || [ $ans == "Y" ] 
then 
    if [ -f $1 ] 
    then 
      mv $1 /home/parallels/dustbin 
      echo "File $1 has been deleted"   
    else 
      echo " File $1 is not found" 
    fi 
else 
    echo "File $1 has not been deleted" 
fi