[Shell] Petit probleme avec un script

Petit probleme avec un script [Shell] - Shell/Batch - Programmation

Marsh Posté le 13-11-2006 à 23:00:48    

Voila, le but du script est de recuperer le contenu du fichier passwd et d'en extraire les informations de base (Nom,Groupe,Repertoire d'accueil et Shell).
 
Le probleme qui se pose a moi est que la fonction read copie le contenu entier de chaque ligne retournée par la boucle for dans la variable $name. Et non dans chacune des variables définies.
 
J'ai pu remarqué que la modification de la variable IFS modifiait le contenu du fichier temporaire que je crée pour stocker les lignes retournées par la boucle for. Quand elle est modifiée en : dans la boucle pour permettre a read d'avoir ce délimiteur de champ précis, on trouve la ligne initiale ou tous les : sont remplacés par des <espaces>.
 
Si quelqu'un peu m'aider a resoudre ca ce serait sympa svp :)
PS: Je sais qu'avec un while read x x x ca marche aussi mais je veux savoir pourquoi comme ceci ca ne marche pas.
PS2: le prof a bloqué comme moi sur ce probleme (étudiant éwi :p), je ne cherche pas la solution de facilité en postant ici donc :)
 

Code :
  1. #!/bin/bash
  2. # **************************************************
  3. # Sauvegarde et modif de la variable IFS
  4. bkp_IFS=$IFS
  5. IFS=$'\n'
  6. echo "Nom Groupe Repertoire Shell"
  7. echo "---------------------------------------"
  8. for var in `cut -d : -f1,4,6,7 passwd.cpy`
  9. do
  10. IFS=':'
  11. echo $var > tmp
  12. read name grp dir shell
  13. echo $name $grp $dir $shell
  14. IFS=$'\n'
  15. done
  16. # Restauration IFS
  17. IFS=$bkp_IFS

Message cité 1 fois
Message édité par Kurrt le 13-11-2006 à 23:04:18
Reply

Marsh Posté le 13-11-2006 à 23:00:48   

Reply

Marsh Posté le 14-11-2006 à 00:23:09    

Je ne comprend pas ton probleme. IFS=':' fait exactement ce que tu veux, non ? Tu te retrouve avec le premier champs dans name, le 2eme dans grp, le 3eme dans dir... Si tu te retrouve avec des espaces au lieu des ":" dans ton fichier temporaire, ce n'est pas que name contient toute ta ligne avec les espaces au lieu des ":"... C'est simplement que echo affichie chacun de ses arguments sperares par des espaces.

Reply

Marsh Posté le 14-11-2006 à 17:06:25    

Kurrt a écrit :

Voila, le but du script est de recuperer le contenu du fichier passwd et d'en extraire les informations de base (Nom,Groupe,Repertoire d'accueil et Shell).


Pas de pb - Exercice de base dans l'apprentissage du shell
 

Kurrt a écrit :

Le probleme qui se pose a moi est que la fonction read copie le contenu entier de chaque ligne retournée par la boucle for dans la variable $name. Et non dans chacune des variables définies.


Comprends rien à ce que tu dis. La fonction "read" (comme dans la syntaxe "read a b c" ) découpe toute ton entrée selon le shéma "a b c" en fonction de l'IFS
- le premier mot va dans "a"
- le second mot va dans "b"
- le reste de la ligne (du 3° mot jusqu'au "return" ) va dans "c"
 

Kurrt a écrit :

J'ai pu remarquer que la modification de la variable IFS modifiait le contenu du fichier temporaire que je crée pour stocker les lignes retournées par la boucle for.


Absolument pas. Tu as pu être trompé par le fait que l'IFS n'est jamais affichable. Donc si tu fais un "echo" dans ton script, partout où il y aura ":" tu verras un espace mais si tu fais "cat tmp" en dehors du script, tu verras tes ":" bien présent.
 

Kurrt a écrit :

Quand elle est modifiée en : dans la boucle pour permettre a read d'avoir ce délimiteur de champ précis, on trouve la ligne initiale ou tous les : sont remplacés par des <espaces>.


Pourquoi faire simple quand on peut faire compliqué.
Déjà on peut se passer du fichier tmp qui implique
- un accès disque donc lent
- un accès concurrent (que se passe-t-il si tu lances 2 fois le même script en parallèle ? => les deux scripts vont se polluer mutuellement via le fichier "tmp" )
 

Kurrt a écrit :

PS2: le prof a bloqué comme moi sur ce probleme


Pas étonnant - Toucher à l'IFS est très dangereux car tout le shell utilise ce séparateur et on se retrouve souvent avec des résultats incohérents voire inexpliquables. Donc si on y touche, autant le faire "bien" et de façon très limitée (on le remet immédiatement après s'en être servi et non en fin de script).
 

#!/bin/bash
old=$IFS
echo "Nom    Groupe    Repertoire    Shell"
echo "---------------------------------------"
cat passwd.cpy |while read ligne
do
    IFS=:
    set $ligne
    IFS=$old
    echo $1 $4 $6 $7
done


 
La structure "cat ... |while read" est une astuce liée au fait que "read" arrête sa lecture à chaque "return" donc à chaque boucle, la variable "ligne" contiendra toute la ligne venue du pipe lui même alimenté par le fichier. Ensuite il n'y a plus qu'à la découper proprement sur le séparateur ":"
 
On peut éviter le pipe en utilisant "exec" qui te crée un autre canal input ou output selon le cas

#!/bin/bash
old=$IFS
echo "Nom    Groupe    Repertoire    Shell"
echo "---------------------------------------"
exec 3<passwd.cpy
while read ligne 0<&3
do
    IFS=:
    set $ligne
    IFS=$old
    echo $1 $4 $6 $7
done


Message édité par Sve@r le 14-11-2006 à 17:09:39

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 14-11-2006 à 17:48:24    

Voici une façon de faire qui fonctionne en KSH, je ne sais pas si elle valide avec BASH.

echo "Nom    Groupe    Repertoire    Shell"  
echo "---------------------------------------"  
while IFS=: read nom password uid gid  groupe home shell
do  
     echo $nom $gid $home $shell  
done < passwd.cpy


 


---------------
Jean Pierre.
Reply

Marsh Posté le 14-11-2006 à 19:07:21    

Merci pour votre aide je vais voir ca par moi meme :)

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed