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 29/09/2011, à 18:35

nassertom

shopt: not found

Bonjour,

J'ai souhaité rendre récursive une boucle "for i" en utilisant "globstat"

#!/bin/bash
shopt -s globstar

for i in "$1"/**/*.mp3;do  

mais le terminal me répond :
2: shopt: not found

je suis en ssh et un man shopt ne fonctionne pas.
Si quelqu'un a une idée ?
D'avance merci

Dernière modification par nassertom (Le 29/09/2011, à 18:35)


C'est la plus radicale manière d'anéantir tout discours que d'isoler chaque chose de tout le reste; car c'est par la mutuelle combinaison des formes que le discours nous est né.
[ Le Sophiste, 259e ]

Hors ligne

#2 Le 29/09/2011, à 19:00

Levi59

Re : shopt: not found

Que se passe-t-il si tu tapes juste "shopt" dans le terminal?

Hors ligne

#3 Le 29/09/2011, à 19:19

pingouinux

Re : shopt: not found

shopt est une "builtin command" de bash. Pour avoir son mode d'emploi :

man bash

et chercher shopt
La boucle fonctionne chez moi, en ajoutant une commande, et done

Modifié :
Mon shell est le bash

Dernière modification par pingouinux (Le 29/09/2011, à 19:21)

Hors ligne

#4 Le 29/09/2011, à 19:39

nassertom

Re : shopt: not found

Merci pour vos messages,

la réponse du terminal est :

autocd             off
cdable_vars        off
cdspell            off
checkhash          off
checkjobs          off
checkwinsize       on
cmdhist            on
compat31           off
compat32           off
compat40           off
dirspell           off
dotglob            off
execfail           off
expand_aliases     on
extdebug           off
extglob            on
extquote           on
failglob           off
force_fignore      on
globstar           off
gnu_errfmt         off
histappend         on
histreedit         off
histverify         off
hostcomplete       off
huponexit          off
interactive_comments    on
lithist            off
login_shell        on
mailwarn           off
no_empty_cmd_completion    off
nocaseglob         off
nocasematch        off
nullglob           off
progcomp           on
promptvars         on
restricted_shell    off
shift_verbose      off
sourcepath         on
xpg_echo           off

sinon effectivement dans mon shell il y a bien un done et une instruction.

et par exemple un echo sur $i me donne une adresse du type :
/home/**/*.mp3
ce qui montre bien que l'instruction shopt n'est pas prise en compte.

Dernière modification par nassertom (Le 29/09/2011, à 19:40)


C'est la plus radicale manière d'anéantir tout discours que d'isoler chaque chose de tout le reste; car c'est par la mutuelle combinaison des formes que le discours nous est né.
[ Le Sophiste, 259e ]

Hors ligne

#5 Le 30/09/2011, à 04:34

nassertom

Re : shopt: not found

Finalement en relançant mon bash il a fonctionné.
Cependant l'utilisation de globstar ne me permet pas d'explorer en profondeur mes répertoires celui ci s'arrête au second niveau ??
ce qui complique mon shell.

Mon besoin est de faire une recherche dans un repertoire source pour chercher un type de fichier. puis de vérifier la présence de chaqu'un de ces fichiers dans une arboréssence Cible. et effectuer un traitement différent en fonction de la présence ou non du fichier dans la cible.

J'ai de ce fait codé vite fait des fonctions récursives pour me permetre de faire ceci, mais comme je suis fainéant et que je me dit qu'il ne sert à rien de réinventer la roue.
savez-vous si il existe quelque chose qui me permete ceci du genre un find avec un exec si vrai et un autre si faux ...

Voici le bout de code que j'ai fait et qui fonctionne sans problème.

D'avance merci (PS : toutes les remarques sur mon code sont bienvenu car j'ai l'envie d'apprendre)

#!/bin/bash
#Paramètres du shell
repertoirSource="/home"
repertoirCible="/mp3"
extension="wma"

flag="non"
actionScript() {
if [ "$flag" = "oui" ] #Si fichier trouvé
    then     
        echo "$1";
        echo existe dans "$2";
    else    #Si fichier non trouvé    
        echo "$1";
        echo "n' existe pas dans" "$2";
    fi 
    return
}
rechercheCible() {
    for u in "$1"/* ;do  #Boucle sur tout le contenu du repertoir passé en paramètre
        if [ -d "$u" ] #Si repertoire
        then
            if [ -f "${u}"/"$2" ] #si le fichier existe dans le répertoire 
            then
                flag="oui"  #valorise le flag pour dire que le fichier est présent                    
                return  #quitte la fonction
            else
                rechercheCible ${u} $2 #sinon explore le contenu de ce nouveau répértoire
            fi
        fi
    done
    return #Si je sorts ici alors c'est que je n'ai rien trouvé...
}
rechercheSource() {
    for i in "$1"/*."$2" ;do #Boucle sur l'ensemble des fichiers dont l'extension est passé en paramètre
        flag="non" #Passe le drapeau à non avant de faire la recherche dans le repertoire cible
        if [ -d "$i" ] #Si repetoire
        then 
            rechercheSource "$i" "$2" #Recherche dans le sous répertoire
        else
            nom="${i##*/}"    #extraction du nom de fichier        
            rechercheCible "$3" "${nom%.*}".mp3 #recherche sa présence dans le répértoire Cible (apres avoir changé son extension
            actionScript "$i" "$3" #Demande l'execution d'une action
        fi
    done
    return
}

rechercheSource "$repertoirSource" "$extension" "$repertoirCible"

echo "Job's done by Tom";

C'est la plus radicale manière d'anéantir tout discours que d'isoler chaque chose de tout le reste; car c'est par la mutuelle combinaison des formes que le discours nous est né.
[ Le Sophiste, 259e ]

Hors ligne

#6 Le 30/09/2011, à 04:58

aduxas

Re : shopt: not found

nassertom a écrit :

Cependant l'utilisation de globstar ne me permet pas d'explorer en profondeur mes répertoires celui ci s'arrête au second niveau ??

Si, ça descend un nombre illimité ( smile ) de niveaux "zero or more directories and  subdirectories".  Du moins, chez moi ça marche.

Hors ligne

#7 Le 30/09/2011, à 05:03

nassertom

Re : shopt: not found

aduxas a écrit :
nassertom a écrit :

Cependant l'utilisation de globstar ne me permet pas d'explorer en profondeur mes répertoires celui ci s'arrête au second niveau ??

Si, ça descend un nombre illimité ( smile ) de niveaux "zero or more directories and  subdirectories".  Du moins, chez moi ça marche.

Je ne comprends vraiment pas pourquoi ça fait cela chez moi alors.


C'est la plus radicale manière d'anéantir tout discours que d'isoler chaque chose de tout le reste; car c'est par la mutuelle combinaison des formes que le discours nous est né.
[ Le Sophiste, 259e ]

Hors ligne

#8 Le 30/09/2011, à 08:00

Postmortem

Re : shopt: not found

Salut,
Sinon, avec un find, pour boucler sur tous les fichiers .ext
d'un répertoire :

while read -rd ''
do
fic_source=${REPLY##*/}
fic_cible=${fic_source/%ext/mp3}
echo "Fichier trouvé dans rep_source : ${fic_source}"
echo "Recherche de ${fic_cible} dans rep_cible..."
find rep_cible -type f -name "${fic_cible}"
done < <(find rep_source -type f -name "*.ext" -print0)

Édit : petite correction pour rechercher un fichier ayant une autre extension.

Dernière modification par Postmortem (Le 30/09/2011, à 15:00)


Mot' a dit : « Un Hellfest sans Slayer, c'est comme une galette-saucisse sans saucisse ! »

Hors ligne

#9 Le 30/09/2011, à 15:43

aduxas

Re : shopt: not found

Donc ceci ne trouve rien?

mkdir -p a/b/c/d
touch a/b/c/d/FIC.txt
shopt -s globstar
ls -l **/*.txt
rm -f a

Hors ligne

#10 Le 01/10/2011, à 17:59

nassertom

Re : shopt: not found

Bonjour,

Désolé de ne pas avoir posté avant.
aduxas je ne comprends pas ton message, c'est une question pour moi ?
Postmortem merci pour ta contribution. à ce jour j'ai quelques difficulter pour comprendre le fonctionnement du shell que tu m'as écrit surtout identifier le sécquencement des traitements.

Dans ce que je comprents tu fais :
1/ un find qui envoi le contenu de ce qu'il trouve dans la boucle while tu utilise print0 pour ne pas être géné par les espaces.
c'est dans le même principe que xarg un peu ?
2/ ${REPLY##*/} tu suprimes le chemin pour ne garder que le nom.
$REPLY est le '$i' du 'For i' in dans une boucle while ?
3/ tu changes l'extension pour faire ta future recherche via find
4/ tu fais un find

Question comment fait tu pour effectuer un traitement différent si il y a un résultat de pas de résultat dans le dernier find ?

Désolé pour mes questions.

Voici mon script finalisé qui je le pense peut être rationalisé.

#!/bin/bash

if [ $# != 2 ] # Test le nombres de paramètre passé au shell
then
    echo erreur dans la saisie des paramètres;
    echo "essayer : sh $0 /repertoire_source /repertoire_cible";
    exit 0 # Quitte le shell
elif [ ! -d "$1" -o ! -d "$2" ] # Test que les paramètres soient bien des repertoires
then
    echo il faut renseigner des répertoirs dans les paramètres;
    exit 0
fi
#Paramètres du shell
repertoirSource="${1%/}/" # Supprime le slash de la fin si il existe puis en ajoute un (pour éviter d'en avoir 2 si l'utilisateur l'avait mis)
repertoirCible="${2%/}/"
extension="mkv"
#Fichiers de log pour exploitation future
log="$repertoirCible"log.txt
existant="$repertoirCible"existant.txt
absent="$repertoirCible"absent.txt
erreur="$repertoirCible"erreur.txt

flag="non" #Drapeau pour communiquer entre les fonctions
maintenant=$(date) #Pour afficher l'heure et la date dans le fichier de log

#Fonction pour mettre à jour la date et heure dans la variable.
actualiseTimeOfTreatment() {
    maintenant=$(date '+%Y-%m-%d %H:%M:%S')
}
#Fonction métier besoin de ripper des fichiers mkv en avi avec une selection automatique de la langue francaise si présente
actionMKVtoAVI() {
    fichier="${1##*/}" #Récupération du nom de fichier passé en paramètre (idem que d'utiliser basename)
    echo "${maintenant};${1};demande de conversion." >> "$log";
        # recherche le mapping des pistes audio FR via la commande ffmpeg -i
        # redirection de la sortie 2 vers la 1 car ffmpeg n'affiche pas les informations à l'écran via la sortie standard.
        # recuperation du resultat de grep dans la variable.
    audio=`ffmpeg -i  "$1" 2>&1| grep '(fre): Audi'`
        # supprime de la variable 'Stream #' ainsi que tous ce qui le precede.
    audio="${audio##*Stream #}"
        # supprime de la variable '(fre)' et tous ce qui suit
    audio=${audio%(fre)*}
        # la variable contien à ce moment là soit le mappage attendu pour le francais (ex: '0.1') soit rien
        # même principe pour le mappage de la vidéo car pour mapper en manuel dans ffmpeg il faut lui donner l'ensemble des flux.
        # recherche le mapping de la video via la commande ffmpeg -i
    video=`ffmpeg -i  "$1" 2>&1| grep ': Video'`
    video="${video##*Stream #}"
    video=${video%%(*}
        # si piste audio FR détecté alors force le map dans la conversion.
        # pas de test sur la variable vidéo car en cas d'erreur c'est ffmpeg qui prendra en charge de mapper automatiquement la première piste vidéo.
    if ["${audio}" -e ""]
    then
        echo "${maintenant};${1};Pas de piste audio française trouvée." >> "$log";
        echo "${maintenant};${1};ffmpeg -i $1 -async 1 -s 720x576 -r 24 -ab 128k -b 1200k -aspect 16:9 -ac 2 -v 0 -f avi ${repertoirCible}${fichier%.*}.avi" >> "$log";
        ffmpeg -i "$1" -async 1 -s 720x576 -r 24 -ab 128k -b 1200k -aspect 16:9 -ac 2 -v 0 -f avi "${repertoirCible}${fichier%.*}".avi;
    else
        echo "${maintenant};${1};Piste audio française trouvée." >> "$log";
        echo "${maintenant};${1};ffmpeg -i $1 -async 1 -s 720x576 -r 24 -ab 128k -b 1200k -aspect 16:9 -map ${video} -map ${audio} -ac 2 -v 0 -f avi ${repertoirCible}${fichier%.*}.avi;" >> "$log";
        ffmpeg -i "$1" -async 1 -s 720x576 -r 24 -ab 128k -b 1200k -aspect 16:9 -map "${video}" -map "${audio}" -ac 2 -v 0 -f avi "${repertoirCible}${fichier%.*}".avi;
    fi 
}
actionScript() {
actualiseTimeOfTreatment #demande de mise à jour de la variable temps (maintenant)
if [ "$flag" = "non" ] #Si fichier non trouvé
    then     
        echo "$1" >> "$absent";
        actionMKVtoAVI "$1"
    else    #Si fichier trouvé    
        echo "${maintenant};${1};${flag}" >> "$log" ;
        echo "$1" >> "$existant";
    fi 
    return
}
rechercheCible() { #Dans le cas des boucles for le résultat d'un repertoir n'est pas fini par un '/' c'est pourquoi je l'ajoute apres ${u}"/"
    for u in "$1"* ;do  #Boucle sur tout le contenu du repertoir passé en paramètre
        if [ -d "$u" ] #Si repertoire
        then
            if [ -f "${u}"/"$2" ] #si le fichier existe dans le répertoire 
            then
                flag="${u}"/"$2"  #valorise le flag pour dire que le fichier est présent                    
                return  #quitte la fonction
            else
                rechercheCible "${u}/" "$2" #sinon explore le contenu de ce nouveau répértoire
            fi
        fi
    done
    return #Si je sorts ici alors c'est que je n'ai rien trouvé...
}
rechercheSource() {
    for i in "$1"* ;do #Boucle sur l'ensemble des fichiers 
        flag="non" #Passe le drapeau à non avant de faire la recherche dans le repertoire cible
        if [ -d "$i" ] #Si repetoire
        then 
            rechercheSource "${i}/"  #Recherche dans le sous répertoire
        else
            currentExtension="${i##*.}" #Extraction de l'extension
            nom="${i##*/}"    #extraction du nom de fichier        
            if [ "$currentExtension" = "${extension}" ]
            then    
                if [ -f "${repertoirCible}${nom%.*}".avi ] #si le fichier existe dans le répertoire cible
                then
                    flag="${repertoirCible}${nom%.*}".avi  #valorise le flag pour dire que le fichier est présent
                    actionScript "$i" #Demande l'execution d'une action    
                else
                    rechercheCible "$repertoirCible" "${nom%.*}".avi #recherche sa présence dans les sous répértoires Cible (apres avoir changé son extension)        
                    actionScript "$i" #Demande l'execution d'une action
                fi
            else
                echo "${maintenant};${1};n'est pas un fichier $extension">> "$log";
                echo "$i" >> "$erreur";
            fi
        fi
    done
    return
}

rechercheSource "$repertoirSource" 

echo "Job's done by Tom";

D'avance merci,


C'est la plus radicale manière d'anéantir tout discours que d'isoler chaque chose de tout le reste; car c'est par la mutuelle combinaison des formes que le discours nous est né.
[ Le Sophiste, 259e ]

Hors ligne

#11 Le 01/10/2011, à 20:01

Postmortem

Re : shopt: not found

nassertom a écrit :

1/ un find qui envoi le contenu de ce qu'il trouve dans la boucle while tu utilise print0 pour ne pas être géné par les espaces.
c'est dans le même principe que xarg un peu ?

find affiche les fichiers trouvés séparés par un retour à ligne par défaut. Avec print0, les fichiers sont séparés par le "caractère null". Cela permet de récupérer correctement les noms de fichiers contenant des retour à la ligne (ce qui est quand même très rare mais bon !) et des espaces.
On s'en sert souvent avec | xargs -0 derrière en effet.
Dans notre cas, le print0 me permet de récupérer correctement le nom du fichier grâce à l'option -d '' de read ; si tu tapes read toto dans le terminal, celui-ci attends que tu tapes du texte puis "entrée", ce texte sera affecté à la variable toto. Avec l'option -d, on dit à read de lire le texte jusqu'au caractère précisé par l'option. Dans notre cas, j'ai mis -d '', donc read lit jusqu'au caractère null (qui est envoyé par -print0 dans find).

nassertom a écrit :

2/ ${REPLY##*/} tu suprimes le chemin pour ne garder que le nom.
$REPLY est le '$i' du 'For i' in dans une boucle while ?

REPLY est la variable utilisée si on ne précise pas de nom de variable après la commande read :

$ read
un texte
$ echo "$REPLY"
un texte
$ read toto
un autre texte
$ echo "$toto"
un autre texte

L'utilisation de la variable REPLY permet aussi de garder les espaces qui interviennent éventuellement avant et après ce que l'on saisi ; une autre variable supprime ces espaces :

$ read
   du texte avec des espaces avant et après   
echo "###$REPLY###"
###   du texte avec des espaces avant et après   ###

$ read toto
  du texte avec des espaces avant et après   
$ echo "###$toto###"
###du texte avec des espaces avant et après###

J'ai aussi précisé l'option -r à read, cela permet de ne pas se faire bouffer les \ qui pourraient apparaître dans les noms de fichier :

$ read toto
texte avec \ dedans
$ echo "$toto"
texte avec  dedans

$ read toto
texte avec \ dedans
$ echo "$toto"
texte avec \ dedans
nassertom a écrit :

Question comment fait tu pour effectuer un traitement différent si il y a un résultat de pas de résultat dans le dernier find ?

Ma première idée serait de récupérer le résultat du find dans une variable et de tester si cette variable est vide ou non... Mais y'a peut-être mieux !

Dernière modification par Postmortem (Le 01/10/2011, à 20:10)


Mot' a dit : « Un Hellfest sans Slayer, c'est comme une galette-saucisse sans saucisse ! »

Hors ligne

#12 Le 03/10/2011, à 02:14

nassertom

Re : shopt: not found

Bonsoir,

Merci d'avoir pris le temps de répondre à chacune de mes questions.
J'espère que bientôt moi aussi je pourrai être de bon conseil.


C'est la plus radicale manière d'anéantir tout discours que d'isoler chaque chose de tout le reste; car c'est par la mutuelle combinaison des formes que le discours nous est né.
[ Le Sophiste, 259e ]

Hors ligne