Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
1861 connectés 

  FORUM HardWare.fr
  Programmation
  Shell/Batch

  [Shell] boucle avec des nom de fichier avec espace

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

[Shell] boucle avec des nom de fichier avec espace

n°1741003
fym37
Posté le 03-06-2008 à 18:52:26  profilanswer
 

Salut,
Je souhaiterai faire :

Code :
  1. for i in `ls`
  2. (traitement sur chaque fichier)


Le problème est que si le répertoire contient des fichiers, ayant des espaces dans leur nom, sa ne marche pas  :(

mood
Publicité
Posté le 03-06-2008 à 18:52:26  profilanswer
 

n°1741010
gilou
Modérateur
Modzilla
Posté le 03-06-2008 à 19:51:06  profilanswer
 

Sauf que le probleme n'est pas sur la ligne 1, mais sur le reste, que tu ne nous a pas détaillé.
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°1741143
matafan
Posté le 04-06-2008 à 09:24:29  profilanswer
 

Si, il y a déjà un problème sur la ligne 1 : il faut qu'il mette des double quotes autour du `ls`, sinon i prendra successivement le nom de chacun des composants de chaque nom de fichier contenant des espaces.
 
Ensuite suivant ce qu'il fait dans la boucle il faudra éventuellement également qu'il mettre des double quotes autour de $i.
 

for i in "`ls`"
do
        abc "$i" def
done

n°1741409
Sve@r
Posté le 04-06-2008 à 15:13:46  profilanswer
 

matafan a écrit :

Si, il y a déjà un problème sur la ligne 1 : il faut qu'il mette des double quotes autour du `ls`, sinon i prendra successivement le nom de chacun des composants de chaque nom de fichier contenant des espaces.
 
Ensuite suivant ce qu'il fait dans la boucle il faudra éventuellement également qu'il mettre des double quotes autour de $i.
 

for i in "`ls`"
do
        abc "$i" def
done



 
Le fait de mettre des guillemets autour du ls ne changera rien. Ou dans le meilleur des cas il prendra l'ensemble de tous les noms comme un seul argument. Mais mettre des guillemets à "$i" est une excellente idée.
 
Puisque le problème vient du for (qui utilise l'espace pour séparer ses éléments), ben faut s'en affranchir. Le read est tout indiqué pour ça puisque lui se cale sur le <return> et que toute ligne (même venant d'une commande) se termine par un <return>...

Code :
  1. #!/bin/bash
  2. ls |while read i
  3. do
  4.   abc "$i" def
  5. done


Petit inconvénient => qui dit pipe dit sous processus. Et donc on ne pourra faire ressortir aucune variable de la boucle. Si ce point ne présente pas de soucis alors c'est bon. Sinon on peut gruger un petit peu en utilisant des parenthèses

Code :
  1. #!/bin/bash
  2. ls |( while read i
  3. do
  4.   abc "$i" def
  5.   var=machin
  6. done
  7. echo $var )


Mais cela ne fait que reporter le problème. Si vraiment on veut s'en affranchir totalement, on ne peut plus utiliser le pipe donc faut passer par un fichier temporaire

Code :
  1. #!/bin/bash
  2. # Création du fichier temporaire
  3. ls >fichier_temporaire
  4.  
  5. # Création du buffer input contenant le fichier
  6. exec 3<fichier_temporaire
  7.  
  8. # Le fichier ne sert plus à rien car il est dans le buffer
  9. rm -f fichier_temporaire
  10.  
  11. # Lecture du buffer
  12. while read i 0<&3
  13. do
  14.   abc "$i" def
  15.   var=machin
  16. done
  17. echo $var


Cette solution évite les problèmes mentionnés précédement mais on entre dans une autre problématique concernant les accès multiples sur le même fichier (si le script est lancé deux fois en parallèle => dommage pour "fichier_temporaire" ) qui ne peut se régler que par la création d'un fichier temporaire au nom unique (en incluant par exemple dans son nom la variable "$$" => n° process)
 
Comme quoi, en partant d'un problème tout con, si on veut tout gérer on peut arriver à des sacrés soucis...

Message cité 1 fois
Message édité par Sve@r le 04-06-2008 à 15:19:20

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
n°1741427
matafan
Posté le 04-06-2008 à 15:35:11  profilanswer
 

Sve@r a écrit :

Le fait de mettre des guillemets autour du ls ne changera rien. Ou dans le meilleur des cas il prendra l'ensemble de tous les noms comme un seul argument.


C'est faux. Tu te t'en serait rendu compte si comme moi tu avais essayé ;)
Pour info l'explication est dans le man de bash :

Citation :

  Command Substitution
       [...]
       If the substitution appears within double quotes,  word  splitting  and
       pathname expansion are not performed on the results.


S'il fait comme j'ai indiqué, ça marchera.

Message cité 1 fois
Message édité par matafan le 04-06-2008 à 15:37:23
n°1741429
gilou
Modérateur
Modzilla
Posté le 04-06-2008 à 15:37:52  profilanswer
 

Citation :

Le fait de mettre des guillemets autour du ls ne changera rien. Ou dans le meilleur des cas il prendra l'ensemble de tous les noms comme un seul argument. Mais mettre des guillemets à "$i" est une excellente idée.

Avec un `ls -Q` on ne recupere pas le nom entre double quotes?. Bon, il y a peut être des options a mettre en plus pour n'avoir que le nom du fichier.
A+,
 


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°1741434
gilou
Modérateur
Modzilla
Posté le 04-06-2008 à 15:41:08  profilanswer
 

matafan a écrit :


C'est faux. Tu te t'en serait rendu compte si comme moi tu avais essayé ;)
Pour info l'explication est dans le man de bash :

Citation :

  Command Substitution
       [...]
       If the substitution appears within double quotes,  word  splitting  and
       pathname expansion are not performed on the results.


S'il fait comme j'ai indiqué, ça marchera.

L'explication en question dit qu'il doit prendre tous les noms comme un seul argument, non?
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°1741509
fym37
Posté le 04-06-2008 à 18:36:10  profilanswer
 

Excusé moi de ne pas avoir été assez clair. Je voulais récupérer chaque nom de fichier .
Merci beaucoup Sve@r c'est ce que je cherchais !

n°1741555
matafan
Posté le 04-06-2008 à 21:47:36  profilanswer
 

Bon j'ai fumé pour le "`ls`", effectivement ça renvoit tout comme un mot.
 
La solution la plus simple c'est quand même "for i in *" ...

n°1742250
Sve@r
Posté le 05-06-2008 à 21:31:12  profilanswer
 

matafan a écrit :

Bon j'ai fumé pour le "`ls`", effectivement ça renvoit tout comme un mot.


Non t'as pas fumé. Auourd'hui j'ai essayé cette syntaxe sur un bash de Fedora Core 7 et effectivement ça marche.
 
Cependant, travaillant dans un milieu hétérogène (avec du sun, du Redhat, du Ubuntu) et étonné de ce résultat qui ne correspondait pas à ce que j'attendais, j'ai testé sur un bash de Solaris puis un ksh => dans les deux cas cela redonne ce que j'avais prévu => un seul mot.
Donc il est probable que cette syntaxe devienne un standard dans le futur mais cela ne l'est pas actuellement et celui qui veut faire un script "portable descendant" ne peut pas l'utiliser.
 
Sinon l'option "ls -Q" de Gilou fonctionne aussi sur FC7 mais pas sur Solaris. Là aussi pas standard.


---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
mood
Publicité
Posté le 05-06-2008 à 21:31:12  profilanswer
 

n°1742318
gilou
Modérateur
Modzilla
Posté le 06-06-2008 à 04:00:20  profilanswer
 

Oui, ls -Q c'est pas Posix, donc pas OSXien, par contre ca a l'air d'être Gnuesque et Linuxien.
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°1943528
HDDSYonex
Posté le 23-11-2009 à 14:56:39  profilanswer
 

Je déterre le sujet pour ceux qui passent et ont le même soucis (on le rencontre assez souvent quand même) une solution assez simple existe:
 

Code :
  1. OLDIFS=$IFS;
  2. IFS=$(echo -en "\n\b" );
  3. for i in `ls`;
  4. do
  5. ...
  6. done;
  7. IFS=$OLDIFS;


 
NB: Si on utilise rien d'autre qui a besoin d'IFS sauvegarder sa valeur n'est même pas obligatoire car une fois le script fini il reprend sa valeur normale.

n°2132663
hologram
Posté le 23-03-2012 à 16:37:25  profilanswer
 

Merci de l'avoir sorti des oubliettes HDDSYonex.
Ca marche nikel :)

n°2132693
Xavier_OM
Monarchiste régicide (fr quoi)
Posté le 23-03-2012 à 18:42:16  profilanswer
 

Tu peux aussi bêtement protéger, t'es pas obligé de changer IFS c'est un peu bourrin :o

for i in "$(ls)"; do  
    echo "$i"
done



---------------
Il y a autant d'atomes d'oxygène dans une molécule d'eau que d'étoiles dans le système solaire.
n°2132790
Profil sup​primé
Posté le 25-03-2012 à 16:48:31  answer
 

salut,
 
et si tout simplement vous utilisiez les possibilités du shell : le développement des chemins

Code :
  1. for f in *; do echo "$f"; done


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  Shell/Batch

  [Shell] boucle avec des nom de fichier avec espace

 

Sujets relatifs
Insertion caractere dans un fichierScript TCL Eggdrop ... Variable dans un fichier txt
Pb d'affichage dans une boucle[shell] Passer stdin à une commande passé au shell sur stdin
[ bash ] date de dernière d'un fichier[Résolu] Newbie - requêtes SQL de sélection et boucle
Chargement fichier externe JS ?Ouvrir un fichier excel en VBA
Fonctions Javascript : dans un fichier .js ou dans le <head> ?[JAVA] [Résolu] Variable Calendar incrémentée dans une boucle
Plus de sujets relatifs à : [Shell] boucle avec des nom de fichier avec espace


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR