IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Shell et commandes POSIX Discussion :

Boucle for et fichiers contenant un espace


Sujet :

Shell et commandes POSIX

  1. #1
    Modérateur
    Avatar de gangsoleil
    Homme Profil pro
    Manager / Cyber Sécurité
    Inscrit en
    Mai 2004
    Messages
    10 150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Manager / Cyber Sécurité

    Informations forums :
    Inscription : Mai 2004
    Messages : 10 150
    Points : 28 119
    Points
    28 119
    Par défaut Boucle for et fichiers contenant un espace
    Bonjour,

    J'essaie de parcourir un répertoire qui contient des fichiers, dont certains ont un espace dans le nom, et je n'y arrive pas...

    Pour créer un répertoire de test :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    mkdir test_toto
    touch "test_toto/this is a test"
    touch "test_toto/not one more"
    Ce qui me pose problème :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    for FILE in $(find test_toto -type f -exec basename {} \; )
    do
      echo "file : >>$FILE<<"
    done
    Sortie :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    file : >>this<<
    file : >>is<<
    file : >>a<<
    file : >>test<<
    file : >>not<<
    file : >>one<<
    file : >>more<<
    Ce que je voudrais obtenir :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    file : >>this is a test<<
    file : >>not one more<<
    Et j'ai beau essayer dans tous les sens, je n'y arrive pas... Une idée à suggérer ?

    Merci
    "La route est longue, mais le chemin est libre" -- https://framasoft.org/
    Les règles du forum

  2. #2
    Modérateur
    Avatar de N_BaH
    Profil pro
    Inscrit en
    Février 2008
    Messages
    7 550
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 7 550
    Points : 19 383
    Points
    19 383
    Par défaut
    Bonjour,

    pourquoi utiliser une boucle ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    find test-toto -type f -exec sh -c 'f=$(basename "$0"); echo "file: >>$f<<"' {} \;
    ...
    ?
    .
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  3. #3
    Modérateur
    Avatar de gangsoleil
    Homme Profil pro
    Manager / Cyber Sécurité
    Inscrit en
    Mai 2004
    Messages
    10 150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Manager / Cyber Sécurité

    Informations forums :
    Inscription : Mai 2004
    Messages : 10 150
    Points : 28 119
    Points
    28 119
    Par défaut
    Citation Envoyé par N_BaH Voir le message
    Bonjour,

    pourquoi utiliser une boucle ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    find test-toto -type f -exec sh -c 'f=$(basename "$0"); echo "file: >>$f<<"' {} \;
    ...
    ?
    J'utilise une boucle car je fais d'autres choses

    J'ai un répertoire qui contient beaucoup de fichiers, et je cherche à mettre tous ces noms de fichiers dans des variables en les séparant par des "|", et en limitant le nombre de caractères dans la variable à 2000 --> Donc j'utilise un tableau KSH :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    MAX_LEN_GREP=2000
    set -A LIST
    i=1
    LIST[$i]=""
    
    for FILE in $(find test_toto -type f -exec basename {} \; )
    do
      LIST[$i]="$FILE|${LIST[$i]}"
      if [[ $(echo ${LIST_EXE[$i]} | wc -c) -gt $MAX_LEN_GREP ]] ##oui, je sais, je coupe a plus que 2000, c est prevu
      then
        (( i += 1 ))
      fi
    
    done
    
    ## Et ici je fais des choses avec LIST[$i]
    
    "La route est longue, mais le chemin est libre" -- https://framasoft.org/
    Les règles du forum

  4. #4
    Modérateur
    Avatar de N_BaH
    Profil pro
    Inscrit en
    Février 2008
    Messages
    7 550
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 7 550
    Points : 19 383
    Points
    19 383
    Par défaut
    Code pdksh : Sélectionner tout - Visualiser dans une fenêtre à part
    find test_toto -type f -print0 | while read -d '' f; do f=$(basename "$f"); echo "construire tableau avec $f"; done
    parce que c'est KSH; dash (c'est à dire le shell le plus POSIX que j'ai à ma disposition) ne reconnaît pas l'option -d de read
    .
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  5. #5
    Modérateur
    Avatar de gangsoleil
    Homme Profil pro
    Manager / Cyber Sécurité
    Inscrit en
    Mai 2004
    Messages
    10 150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Manager / Cyber Sécurité

    Informations forums :
    Inscription : Mai 2004
    Messages : 10 150
    Points : 28 119
    Points
    28 119
    Par défaut
    Tout d'abord, merci beaucoup pour ta réponse.

    Maintenant, y'a un truc que je ne comprends pas : lorsque je tape find . -type f -print0 | while read -d '' f; do f=$(basename $f) ; echo $f ; done dans mon terminal, il affiche bien le resultat escompté. Mais dans mon script, la même ligne n'affiche rien du tout....

    Je sais que suis fatigué, mais quand même, le echo devrait bien afficher quelque chose, non ??
    "La route est longue, mais le chemin est libre" -- https://framasoft.org/
    Les règles du forum

  6. #6
    Modérateur
    Avatar de jlliagre
    Homme Profil pro
    Ingénieur support avancé & développement
    Inscrit en
    Juin 2007
    Messages
    2 695
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur support avancé & développement
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 2 695
    Points : 7 882
    Points
    7 882
    Par défaut
    Il faudriat que tu en dises plus sur ton script et ton terminal.

    De toute façon, "-print0" n'est pas POSIX, pas plus que le tableaux ("set -A") ou la lecture délimitée ("read -d").

    Voici une suggestion qui devrait marcher sous tout système POSIX, sous réserve qu'il n'y a pas de nom de fichier avec un saut de ligne à l'interieur:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    find /tmp -type f -exec basename {} \; | (
    while read file ; do
      echo $file
      [ $# -gt 0 ] && set -- "$@" "$file" || set -- "$file"
    done
     
    for f do
      echo ">>> $f <<<"
    done
    )
    ɹǝsn *sıɹɐlos*

  7. #7
    Modérateur
    Avatar de gangsoleil
    Homme Profil pro
    Manager / Cyber Sécurité
    Inscrit en
    Mai 2004
    Messages
    10 150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Manager / Cyber Sécurité

    Informations forums :
    Inscription : Mai 2004
    Messages : 10 150
    Points : 28 119
    Points
    28 119
    Par défaut
    Bonjour,

    Merci pour ce bout de code, qui fonctionne super bien !

    Pour ce qui est de mon script, il a pour but de construire une liste de fichiers séparés par des "|", pour les passer dans grep. Mais comme j'ai de très nombreux fichiers, et que grep ne supporte pas plus de 2048 caractères, il faut que je le fasse en plusieurs fois, d'où l'utilisation d'un tableau.

    Pour mon terminal, le script doit pouvoir s'exécuter quel que soit le terminal normalement, puisqu'il doit s'exécuter sur des Linux et sur des Unix -- d'où l'utilisation de ksh.

    Dernière question : que fait cette ligne [ $# -gt 0 ] && set -- "$@" "$file" || set -- "$file"et pourquoi l'as-tu mise, sachant que mes premiers tests montrent que $file contient bien les noms de fichiers corrects, même sans cette ligne ?
    [Edit] J'ai bien compris qu'elle permet de passer des attributs aux fichiers, mais je ne comprends toujours pas son utilité.
    "La route est longue, mais le chemin est libre" -- https://framasoft.org/
    Les règles du forum

  8. #8
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 101
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côtes d'Armor (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique en retraite

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 101
    Points : 5 849
    Points
    5 849
    Par défaut
    Citation Envoyé par jlliagre Voir le message
    Voici une suggestion qui devrait marcher sous tout système POSIX, sous réserve qu'il n'y a pas de nom de fichier avec un saut de ligne à l'interieur:
    Peux-tu expliquer pourquoi tu passes par "set"?

    Quelle différence y a-t-il avec un simple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    find /tmp -type f -exec basename {} \; |
    while read file ; do
      echo ">>> $file <<<"
    done

  9. #9
    Modérateur
    Avatar de jlliagre
    Homme Profil pro
    Ingénieur support avancé & développement
    Inscrit en
    Juin 2007
    Messages
    2 695
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur support avancé & développement
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 2 695
    Points : 7 882
    Points
    7 882
    Par défaut
    Gangsoleil a précisé qu'il avait besoin d'un tableau. La seule différence avec une boucle simple est que j'initialise un tableau dans une première étape.

    Le traitement peut être ensuite effectué dans une deuxième étape, ou plusieurs, ou passé à des fonctions. C'est plus souple.

    Le seul tableau supporté par le shell POSIX étant la liste des arguments, c'est ce tableau que je construit laborieusement avec la ligne:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    [ $# -gt 0 ] && set -- "$@" "$file" || set -- "$file"
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    $ set -- "toto"
    $ echo $*
    toto
    $ set -- "$@" titi
    $ echo $*
    toto titi
    $ set -- "$@" tata
    $ echo $*
    toto titi tata
    ɹǝsn *sıɹɐlos*

  10. #10
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 101
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côtes d'Armor (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique en retraite

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 101
    Points : 5 849
    Points
    5 849
    Par défaut
    Citation Envoyé par gangsoleil Voir le message
    Pour ce qui est de mon script, il a pour but de construire une liste de fichiers séparés par des "|", pour les passer dans grep. Mais comme j'ai de très nombreux fichiers, et que grep ne supporte pas plus de 2048 caractères, il faut que je le fasse en plusieurs fois, d'où l'utilisation d'un tableau.
    Il me semble que "xargs" permet justement d'outrepasser la taille des arguments passés à une commande comme "grep", non?

    Ne serait-ce pas une solution plus élégante (car plus simple) à ton problème, plutôt que de couper la liste d'arguments en petits bouts?

    Avis des spécialistes?

  11. #11
    Expert éminent sénior Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 278
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Décembre 2012
    Messages : 4 278
    Points : 12 726
    Points
    12 726
    Par défaut
    Bonjour,

    L'avantage de passer par un set (ou un tableau), c'est que l'on peut y mettre des metacaractere comme '*' par exemple et les utiliser ensuite en tant que metacaractere (sans passer par un eval).
    L'autre, c'est que l'on a déjà construit la liste et que l'on peut encore l'utiliser pour d'autre actions, ce qui devient un peu plus pénible à faire avec xargs.
    Après, la question que je me pose dans le cas présent, c'est quel est le nombre d'argument possible adressable par set ?

    Autre question (qui rejoint l'idée du xargs): pourquoi ne pas créer un fichier de paramètre pour la commande grep (POSIX supporte la forme "-f" de grep) ?
    Bien sur, c'est en supposant que ton but est de créer le pattern de recherche pour grep
    Cordialement.

  12. #12
    Modérateur
    Avatar de gangsoleil
    Homme Profil pro
    Manager / Cyber Sécurité
    Inscrit en
    Mai 2004
    Messages
    10 150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Manager / Cyber Sécurité

    Informations forums :
    Inscription : Mai 2004
    Messages : 10 150
    Points : 28 119
    Points
    28 119
    Par défaut
    Bonjour,

    Mon but est bien de creer un pattern multiple pour egrep, dans un script KSH, qui doit être capable de s'exécuter sur plusieurs environnements plus ou moins bienveillants, d'où mes soucis. Pour xargs, je crains de ne pas pouvoir me baser dessus, car je ne suis pas certain du nombre de caractères qu'il est capable de gérer sur mes différents environnements.

    La solution retenue pour l'instant est de rediriger la sortie du find dans un fichier temporaire, et de lire celui-ci avec une boucle while pour construire mon tableau en KSH (set -A). c'est peut-etre pas ideal, mais ca a l'air de fonctionner pour le moment
    "La route est longue, mais le chemin est libre" -- https://framasoft.org/
    Les règles du forum

  13. #13
    Expert éminent sénior Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 278
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Décembre 2012
    Messages : 4 278
    Points : 12 726
    Points
    12 726
    Par défaut
    Ok,
    Est ce que ton pattern ne peut être qu'exclusif pour une ligne donnée, exemple:
    le pattern ressemble à "toto|titi|tata", est-ce que pour une ligne donnée, je peux avoir à la fois toto et titi ou ne peux en avoir qu'un et un seul ?

    Si c'est "un seul possible", dans ce cas, egrep -f <fichier_resultat_find> fichier(s) semblerait suffisant

    Et dans l'autre cas, pour éviter les lignes en doublons, je passerais plus par awk que par egrep
    Cordialement.

  14. #14
    Modérateur
    Avatar de jlliagre
    Homme Profil pro
    Ingénieur support avancé & développement
    Inscrit en
    Juin 2007
    Messages
    2 695
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur support avancé & développement
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 2 695
    Points : 7 882
    Points
    7 882
    Par défaut
    Citation Envoyé par disedorgue Voir le message
    Après, la question que je me pose dans le cas présent, c'est quel est le nombre d'argument possible adressable par set ?
    La limitation n'est pas en nombre d'argument mais concerne la taille maximale de l'environnement. Il inclut les variables d'environnement et le tableau des arguments (set).

    Sa taille est de ARG_MAX et doit être au moins de _POSIX_ARG_MAX (>= 4096 octets).

    Les valeurs d'un OS (ex: Solaris ici) sont récupérables avec la commande getconf:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    # getconf _POSIX_ARG_MAX
    4096
    # getconf ARG_MAX
    1048320
    ɹǝsn *sıɹɐlos*

  15. #15
    Modérateur
    Avatar de gangsoleil
    Homme Profil pro
    Manager / Cyber Sécurité
    Inscrit en
    Mai 2004
    Messages
    10 150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Manager / Cyber Sécurité

    Informations forums :
    Inscription : Mai 2004
    Messages : 10 150
    Points : 28 119
    Points
    28 119
    Par défaut
    Avant même ça, je suis confronté au problème que ma ligne dépasse la longueur maximale d'une LIGNE, à savoir LINE_MAX, qui vaut 2048 sur les systèmes que j'utilise.
    "La route est longue, mais le chemin est libre" -- https://framasoft.org/
    Les règles du forum

  16. #16
    Modérateur
    Avatar de jlliagre
    Homme Profil pro
    Ingénieur support avancé & développement
    Inscrit en
    Juin 2007
    Messages
    2 695
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur support avancé & développement
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 2 695
    Points : 7 882
    Points
    7 882
    Par défaut
    Citation Envoyé par gangsoleil Voir le message
    Avant même ça, je suis confronté au problème que ma ligne dépasse la longueur maximale d'une LIGNE, à savoir LINE_MAX, qui vaut 2048 sur les systèmes que j'utilise.
    Tu peux mettre des lignes de continuation pour contourner ce problème.
    ɹǝsn *sıɹɐlos*

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 9
    Dernier message: 29/04/2008, 13h38
  2. Nom de fichier contenant un espace
    Par fredo78 dans le forum Mise en forme
    Réponses: 2
    Dernier message: 15/12/2007, 13h12
  3. Boucle for sur fichiers sauf un !
    Par coincoin22 dans le forum Linux
    Réponses: 4
    Dernier message: 13/08/2007, 14h41
  4. Réponses: 2
    Dernier message: 22/05/2006, 00h07
  5. Renommer des fichiers contenant des espaces
    Par MatRem dans le forum Linux
    Réponses: 6
    Dernier message: 28/04/2006, 08h21

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo