Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 15/07/2018, à 21:54

Arthemus

Problème script BASH "opérateur unaire attendu"

Bonjour à tous,

Je suis un débutant sur Ubuntu et je suis le cours d'OpenClassRooms sur "Reprenez le contrôle grâce à Linux", j'avoue me prendre vraiment au jeu et découvrir tout ce que l'on peut faire avec une console, et le fameux bash !!!
À la fin de ce cours nous avons une activités dont je vous passe les détails et on nous demande de faire preuve d'inventivité, du coup j'ai tenté de faire un petit quelque chose mais, même s'il fonctionne très bien, il me renvoi systématiquement le même type d'erreur lorsque je le test sans tout les paramètre activé :

"ligne 22 : [: = : opérateur unaire attendu"   ==>S'affiche uniquement si je lance la commande : ./monbash.sh
"ligne 65 : [: = : opérateur unaire attendu"   ==>S'affiche quand je lance la commande : ./monbash.sh ET ./monbash.sh dico.txt

Cependant le programme acceptant un deuxième paramètre : Filtre, quand je lance la commande : ./monbash.sh dico.txt Filtre ==> tout se passe bien oO

Honnêtement je suis perdu, ça fait 10h que je bosse dessus, que je vais partout voir sur le net, j'ai tenté le manuel mais même lui ne suffit pas à palier à mon incompétence hmm
Je m'avoue vaincu, j'ai envie de prendre la solution facile et de faire un programme moins complexe (pour mon niveau, c'est mon premier xD), mais voila, je me suis vraiment éclaté à le faire et du coup j'ai pas envie de "bâcler" le travail.

J'espère vraiment que vous arriverez à m'expliquer d'où vient le problème, pour que je puisse comprendre.

voila ma fameuse création "echo 'rire dément"

#!/bin/bash

#vérification du paramètre
if [ -z $1 ] || [ ! $1 = "dico.txt" ] 
then
        echo "Paramètre manquant ou paramètre différent de 'dico.txt'"
else
	echo "Paramètre 'dico.txt' accepté"
	verif1="on"	#On place une variable 1 qui va nous servir à lancer le programme dans de bonne condition
fi
sleep 1 	#On endort le programme 1 seconde

#vérification de la présence de dico.txt
if [ -e "dico.txt" ]
then 
	echo "dico.txt présent"
	verif2="on"	#On place une variable 2 qui va nous servir à lancer le programme dans de bonne condition
else
	echo "Impossible de trouver le fichier 'dico.txt'"
fi

if [ $verif1 = "on" ] && [ $verif2 = "on" ] 	#On vérifie que les variable 1 ET 2 sont activée, qu'il y a le paramètre ET le dico
then 	#On grep chaque lettre depuis le fichier dico.txt, on en retire le nombre de ligne où cette lettre apparait (comme il y a un mot par ligne, on connait le nombre de mot qui comprend cette lettre, puis on extrait ce nombre vers un fichier .langstattmp auquel on ajoute en début de ligne la phrase "'lettre correspondante' = " 
	grep A dico.txt | wc -l >> .langstattmp | echo -n "A = " >> .langstattmp
	grep B dico.txt | wc -l >> .langstattmp | echo -n "B = " >> .langstattmp
	grep C dico.txt | wc -l >> .langstattmp | echo -n "C = " >> .langstattmp
	grep D dico.txt | wc -l >> .langstattmp | echo -n "D = " >> .langstattmp
	grep E dico.txt | wc -l >> .langstattmp | echo -n "E = " >> .langstattmp
	grep F dico.txt | wc -l >> .langstattmp | echo -n "F = " >> .langstattmp
	grep G dico.txt | wc -l >> .langstattmp | echo -n "G = " >> .langstattmp
	grep H dico.txt | wc -l >> .langstattmp | echo -n "H = " >> .langstattmp
	grep I dico.txt | wc -l >> .langstattmp | echo -n "I = " >> .langstattmp
	grep J dico.txt | wc -l >> .langstattmp | echo -n "J = " >> .langstattmp
	grep K dico.txt | wc -l >> .langstattmp | echo -n "K = " >> .langstattmp
	grep L dico.txt | wc -l >> .langstattmp | echo -n "L = " >> .langstattmp
	grep M dico.txt | wc -l >> .langstattmp | echo -n "M = " >> .langstattmp
	grep N dico.txt | wc -l >> .langstattmp | echo -n "N = " >> .langstattmp
	grep O dico.txt | wc -l >> .langstattmp | echo -n "O = " >> .langstattmp
	grep P dico.txt | wc -l >> .langstattmp | echo -n "P = " >> .langstattmp
	grep Q dico.txt | wc -l >> .langstattmp | echo -n "Q = " >> .langstattmp
	grep R dico.txt | wc -l >> .langstattmp | echo -n "R = " >> .langstattmp
	grep S dico.txt | wc -l >> .langstattmp | echo -n "S = " >> .langstattmp
	grep T dico.txt | wc -l >> .langstattmp | echo -n "T = " >> .langstattmp
	grep U dico.txt | wc -l >> .langstattmp | echo -n "U = " >> .langstattmp
	grep V dico.txt | wc -l >> .langstattmp | echo -n "V = " >> .langstattmp
	grep W dico.txt | wc -l >> .langstattmp | echo -n "W = " >> .langstattmp
	grep X dico.txt | wc -l >> .langstattmp | echo -n "X = " >> .langstattmp
	grep Y dico.txt | wc -l >> .langstattmp | echo -n "Y = " >> .langstattmp
	grep Z dico.txt | wc -l >> .langstattmp | echo -n "Z = " >> .langstattmp
	
	sort -t= -k 2 -nr .langstattmp 		#On trie l'ensemble du fichier .langstattmp par ordre numérique en prenant en compte la deuxième colonne en partant de "=" et on les affichent sur le terminal
	rm .langstattmp		#On supprimme le fichier temporaire ".langstattmp" qui nous à servit à stocker nos informations, ceci à pour effet de rendre le dossier plus propre et de réinitiliser le ".langstattmp. si on relance le programme (sinon la redirection utilisée plus haut se stackerait et fausserait le résultat)
else
	echo "Lire les mesages d'erreurs" 	#Au cas où l'une des conditions, liées aux variables, ne soient pas remplies
fi

if [ -z $2 ] || [ ! $2 = "Filtre" ]

then
	echo "Vous n'avez pas trouvé le paramètre caché"
else  
	verif3="on"
fi
#On introduit le deuxième paramètre
if [ $verif3 = "on" ]
then 
	echo -e "Ce paramètre vous permet de filtrer les mots du dico.txt, afin de ne retenir que les mots contenant les lettres que vous choisirez au fur et à mesure de ce programme.\n choisissez une lettre :" 
	read var 		       #On lui permet d'écrire
	vari=$var		       #On retient son écriture sous forme de variable
	echo "Le nombre de mot possibe est : " 
	grep $vari dico.txt | wc -l		#On grep les mots contenant cette lettre et on affiche le résultat sur le terminal
	grep $vari dico.txt > .var	#On retient le résultat dans un fichier pour un usage futur		

sleep 1 #On endort le programme 1 seconde

while [ -z $var2 ] || [ $var2 != 'fin' ] #ceci nous permet d'introduire une boucle afin de continuer l'opération auant que l'utilisateur le souhaite
do
	read -p "tapez 'fin' pour choisir une DERNIERE lettre ou n'importe quoi d'autre pour continuer: " var2	#On introduit le choix de sortir du programme
	echo "choisissez une autre lettre : " 
	read var 		       #On lui permet d'écrire
	vari=$var		       #On retient son écriture sous forme de variable
	echo "Le nombre de mot possibe est maintenant : " 
	grep $vari .var | wc -l		#On grep les mots contenant cette lettre et on affiche le résultat sur le terminal
	grep $vari .var > .varbis	#On retient le résultat dans un fichier pour un usage futur
	rm .var		#On supprime l'ancien .var
	mv .varbis .var		#On renomme .varbis en .var
done
	echo "voici la liste des mots que vous avez filtré"
	grep $vari .var #On affiche le résultat
	rm .var 
fi
exit

Merci beaucoup, si vous prenez le temps de lire et de m'aider (je coure faire ma présentation, et manger mon premier repas de la journée accessoirement xD)

Arthemus

Hors ligne

#2 Le 15/07/2018, à 22:17

pingouinux

Re : Problème script BASH "opérateur unaire attendu"

Bonsoir,
Il faut mettre les variables entre " " :
Par exemple :

if [ -z "$1" ] || [ ! "$1" = "dico.txt" ]
while [ -z "$var2" ] || [ "$var2" != 'fin' ]

Hors ligne

#3 Le 15/07/2018, à 22:22

Zakhar

Re : Problème script BASH "opérateur unaire attendu"

L'erreur dans ta ligne 22 vient d'un oubli de "quotes".

Toujours, toujours, toujours, toujours, toujours (j'en ai mis assez pour que ça rentre !) "quoter" tes variables.

On peut à la rigueur ne pas les "quoter" si on est absolument sûr et certain que la variable en question contient toujours dans 100% des cas un nombre et n'est pas vide ou non initialisée. Mais comme les "quotes" marchent aussi en présence de nombres, la bonne pratique est toujours de "quoter".

En effet, dans ton cas tu as des variables vides puisque elles sont initialisées seulement si tu passes dans la bonne branche du test.

Tu est donc en train de comparer :

[ ="on"]

ce qui à l'évidence ne fonctionne pas !

Personnellement j'écris toujours :

if [ "${verif1}" = "on" ] && [ "${verif2}" = "on" ]

- Toujours "quote"
- les {} sont facultatifs pour une variable seule, mais ça permet de visualiser rapidement qu'on a une variable.

Bien sûr, tu peux cochonner et ne pas respecter la bonne pratique de systématiquement "quoter" tes variables, et une autre solution est donc d'être certain que tes variables contiennent quelque chose pour que le test n'échoue pas.
Donc si tu commences ton programme par

verif1="off"
verif2="off"

Ca marche aussi... même sans quote... mais tu risque d'avoir du mal à maintenir ton programme dans le futur !


Deuxième bonne pratique... pourquoi utiliser bash si tu n'en as pas besoin !

Ton script a l'air assez simple et écrit dans "particularisme" à un interprêteur shell particulier, donc commencer par

#! /bin/sh

Permettra à la machine sur lequel le script tourne d'utiliser son interprêteur de script par défaut. Pour Ubuntu, c'est dash depuis un fameux bail. dash est largement plus rapide que bash.
Le seul truc à vérifier c'est ton "read", comme c'est un commande interne, il est possible qu'il faille un peu adapter.

J'ai adopté cette "bonne pratique", le jour où j'ai tenté de faire tourner un de mes scripts sur mon Synology qui n'a pas bash (par défaut) et utilise ash.
Écrire "compatible" est toujours une bonne idée quand tu peux le faire simplement.

Dernière modification par Zakhar (Le 15/07/2018, à 22:30)


"A computer is like air conditioning: it becomes useless when you open windows." (Linus Torvald)

Hors ligne

#4 Le 15/07/2018, à 23:22

Arthemus

Re : Problème script BASH "opérateur unaire attendu"

Oh !!!! PUREEEEE !!! ça FONCTIONNNE !!!
Merci, mille merci, en vrai ça fait 10h que je galère... et vous, vous arrivez comme ça et BIM ça fait des chocapics <3

J'ai bien pris note de vos précieux conseil, j'ai tout quoté, j'ai mis des {...} et j'aime même rajouté au début du script :

verif1="off"
verif2="off"
verif3="off"

Zakhar, pour le bash, c'est imposé hmm
Mais merci beaucoup pour l'explication relative à la comptabilité, j'en prend bonne note pour mes futurs création.
Par "read" est une commande interne, tu entends qu'elle est relative à Ubuntu ou à un paquet et pas à "bash" ?

Encore merci.

Hors ligne

#5 Le 16/07/2018, à 03:04

MicP

Re : Problème script BASH "opérateur unaire attendu"

Bonjour Arthemus

Les "commandes internes" (builtins) dont on parle ici
sont celles dont le code est intégré dans l'interpréteur de commandes (shell) .

L'interpréteur de commande interactif par défaut d'un compte utilisateur sous ubuntu est /bin/bash

Donc, il s'agit des commandes internes du programme /bin/bash

=======
Il existe d'autres interpréteurs de commandes (comme par exemple /bin/dash /bin/ksh /bin/csh etc.) qui ont aussi leur commandes internes
mais dont l'utilisation et le comportement, même si le nom de la commande est le même, peut être légèrement différent.

=======
Tu pourras visualiser la page du manuel des commande internes du bash
en lançant la ligne de commande suivante :

man bash-builtins

et pour visualiser la page du manuel des commande internes du bash
en allant directement à la première ligne du paragraphe concernant
la commande interne read du bash :

man --pager="less -p 'read '" bash-builtins

Dernière modification par MicP (Le 16/07/2018, à 04:38)

Hors ligne

#6 Le 16/07/2018, à 05:37

pingouinux

Re : Problème script BASH "opérateur unaire attendu"

Autre façon d'obtenir le mode d'emploi d'une commande interne :

help commande_interne

help est aussi une commande interne

help help

Hors ligne

#7 Le 16/07/2018, à 08:11

Hizoka

Re : Problème script BASH "opérateur unaire attendu"

@Zakhar : Pas besoin de quote avec [[ ... ]] tongue


KDE Neon 64bits
Tous mes softs (MKVExtractorQt, HizoSelect, HizoProgress, Qtesseract, Keneric, Services menus...) sont sur github

Hors ligne