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 28/09/2007, à 17:42

ploc

[résolu] script bash de copie de répertoires aléatoirement choisis

Bonjour,

Bien qu'étant utilisateur d'Ubuntu, je suis adepte de quelques scripts bash (ou autre) qui sont très simples et font leur boulot très efficacement et très rapidement. Conjugués à tilda, mon bureau devient ce dont je peux rêver de mieux en matière d'ergonomie.

Bref, j'ai quelques scripts qui me permettent d'écouter ma collection de musique organisée comme suit :

/.../mamusique/artiste/album/chanson1.ogg
/.../mamusique/artiste/album/chanson2.mp3

J'ai tout d'abord un script qui enregistre les tag id3 et ogg en récupérant les informations artiste, album et chanson dans le chemin du fichier.

J'ai également un script tout con appelé music.sh qui sélectionne un répertoire artiste au hasard pour le jouer (avec ogg123 ou mpg321 selon). C'est tout simple et ça permet d'écouter un peu tout ça musique car quand on en a beaucoup on a tendance à écouter plus les artistes dont le nom commence par A car ils apparaissent en premier dans la liste. Autant dire que ZZTop n'est pas souvent à l'affiche avec ce principe. Avec mon script, ZZTop a autant de chance que Aldebert de sortir sur mes enceintes.

Ces 2 scripts sont disponibles pour qui veut.

En revanche, j'ai également un lecteur de musique portable qui se connecte en usb et est monté sur le bureau comme une clé usb. Pour ce lecteur aussi j'aimerai un petit script qui me permette simplement de :
- vider ou non le lecteur (selon les options passées en paramètre)
- sélectionner un artiste au hasard et le copier sur le lecteur, puis recommencer jusqu'à ce que ce dernier soit plein
- renommer les répertoires et fichiers afin de permettre la copie car ext3 et fat32 (le format de beaucoup de lecteurs) n'autorisent pas les mêmes caractères spéciaux
- gérer les éventuelles erreurs pouvant survenir

Je crois avoir déjà vu passer un script effectuant tout ou partie des opérations sus-mentionnées, peut-être sur un blog francophone mais je ne suis pas sûr... j'ai parcourus le planet d'Ubuntu-fr, linuxfr mais je ne trouve trace d'un tel script. Même Gogol ne m'apporte aucune réponse satisfaisante...

Alors, suis-je le seul à vouloir automatiser quelques taches répétitives ? Si quelqu'un se souvient d'un script ici ou là, même s'il ne répond pas à tous mes besoins, ou bien si quelqu'un de très motivé en shell a envie de s'y frotter (je veux bien faire le testeur). En tout cas, je voudrais bien éviter de réinventer la roue, si elle existe déjà...

Merci de m'avoir lu !

Dernière modification par ploc (Le 01/05/2008, à 18:16)

Hors ligne

#2 Le 28/09/2007, à 18:19

Yannick_LM

Re : [résolu] script bash de copie de répertoires aléatoirement choisis

- renommer les répertoires et fichiers afin de permettre la copie car ext3 et fat32 (le format de beaucoup de lecteurs) n'autorisent pas les mêmes caractères spéciaux

Pour ça, je recommande convmv.
Après pour le reste, je sais pas.

<mode cruel>
Mais tu m'as l'air d'avoir le niveau nécessaire pour écrire ce qu'il te faut tout seul ...
</mode cruel>

Dernière modification par Yannick_LM (Le 28/09/2007, à 18:19)


Trucs et astuces pour Vim
Ma web page  avec des trucs dessus ...

Hors ligne

#3 Le 22/04/2008, à 23:12

ploc

Re : [résolu] script bash de copie de répertoires aléatoirement choisis

D'après la doc, l'utilitaire convmv permet de modifier le nom des fichiers passer d'un jeu de caractères à un autre (du genre iso latin vers utf8). Il ne sert pas à rendre un nom de fichier fat32-compatible...

Il faut donc renommer les répertoires et fichiers à l'aide d'une fonction faite à la main, ou bien trouver un autre utilitaire...

Hors ligne

#4 Le 22/04/2008, à 23:16

ploc

Re : [résolu] script bash de copie de répertoires aléatoirement choisis

En l'absence de script existant répondant à mon besoin, je me suis résolu à écrire mon propre script.

C'est une seconde version, elle fonctionne mais n'est pas encore ni parfaite ni robuste.

Toute contribution, remarque ou suggestion constructive est la bienvenue !

Bonne musique (ou bon random, car en fait on peu copier n'importe quoi avec ce script...)

Ploc


#!/bin/bash
#
# randomfeed
# v0.6
# random fill a directory
# author : Ploc
# licence : GPLv3

# default config
defaultFromDir="/media/musicLibrary/"
defaultDestDir="/media/musicPlayerFlashDisk/"

defaultFromDirExcludeRegex=".*temp.*"
defaultDestDirExcludeRegex=".*SETTINGS.DAT"

defaultKeepFiles="no"
defaultMaxSize=400 # in ko
defaultLogLevel=2
defaultLogFile="${HOME}/$(basename "${0}" .sh).log"
defaultFat32CompatibleMode="no"
defaultTestMode="no"

defaultFindDepth=3

# functions

###
 # display help
 ##
displayHelp () {
    cat <<EOF
$(basename "${0}") fills a directory randomly picking directories from another directory.

It can either stop processing when the destination directory is full or when the destination directory reaches a maximum size parameter. It can also remove any file in the destination directory before processing. A test mode is available that does not copy any file (beware of infinite loop).

EOF
    displayUsage
    cat <<EOF

Available optionnal parameters are :
  -h  - display help
  -f  - set path/to/dir/ directory where the data come from
  -d  - set path/to/dir/ directory where the data are copied
  -fr - set regex to exclude some item from being copied
  -dr - set regex to exclude some item from being deleted from the destination directory (useless if -k is set)
  -k  - keep data on destination directory (otherwise destination directory will be emptied)
  -s  - set the maximum size of the destination directory (in ko)
  -ll - set the log level
  -lf - set the log file
  -c  - enable fat 32 compatible mode
  -t  - enable test mode (nothing is copied neither deleted)
EOF
}

###
 # display usage
 ##
displayUsage () {
    cat <<EOF
usage - $(basename "${0}") [-h] [-f path/to/dir/] [-d path/to/dir/] [-fr regex] [-dr regex] [-k] [-s size_in_ko] [-ll logLevel] [-lf logFile] [-c] [-t]
EOF
}

###
 # log a message
 #
 # @global $logLevel the log level
 # @global $logFile the log file
 # @param $1 the log level of the message
 # @param $2 the log message
 ##
log () {
    local paramLogLevel=${1}
    local paramLogMessage=${2}

    local logDate=$(date +%H:%M:%S)
    local logMessage="[${logDate}] ${paramLogMessage}"

    if [ "${paramLogLevel}" -le "${logLevel}" ] ; then
        echo "${logMessage}"
    fi

    if [ ! -z "${logFile}" ] ; then
        echo "${logMessage}" >> "${logFile}"
    fi
}

###
 # get a random directory
 #
 # @global $defaultFindDepth the default find depth
 # @param $1 the from directory
 # @return $randomDir the random directory
 ##
getRandomDir () {
    local paramFromDir=${1}

    local nbLines="$(find -L "${paramFromDir}" -mindepth ${defaultFindDepth} -maxdepth ${defaultFindDepth} -type d | wc -l)"

    if [ ${nbLines} -eq 0 ] ; then
        log 1 "cannot find anything in ${paramFromDir}"
        exit 6
    fi

    local lineNumber=$(( $(( ${RANDOM} % ${nbLines} )) + 1 ))
    randomDir="$(find -L "${paramFromDir}" -mindepth ${defaultFindDepth} -maxdepth ${defaultFindDepth} -type d | head -"${lineNumber}" | tail -1)"
}

###
 # copy a directory
 #
 # @global $fromDir
 # @global $destDir
 # @param $1 the random / from directory
 # @param $2 the dest directory
 # @param $3 the from exclude regex
 ##
copyDir () {
    local paramFromDir=${1}
    local paramDestDir=${2}
    local paramFromDirExcludeRegex=${3}
    
    log 2 "= copying dir from ${paramFromDir} to ${paramDestDir}"

    find "${paramFromDir}" -type f -not -regex "${paramFromDirExcludeRegex}" |
    {
        while read ligne
        do
            copyFile "${ligne:${#fromDir}}" "${fromDir}" "${paramDestDir}" 
        done
    }
}

###
 # copy a file
 #
 # @global $fat32CompatibleFileNames
 # @global $testMode
 # @param $1 the file to copy
 # @param $2 the from directory
 # @param $3 the dest directory
 ##
copyFile () {
    local paramFile=${1}
    local paramFromDir=${2}
    local paramDestDir=${3}

    if [ "${fat32CompatibleMode}" = "yes" ] ; then
        local newFileName="$(echo "${paramFile}" | tr ":*?\"<>|" "_______")"
    else
        local newFileName=${paramFile}
    fi

    local newPathName="$(dirname "${newFileName}")"

    if [ ! -d "${paramDestDir}${newPathName}" ] ; then
        log 3 "+ creating directory ${paramDestDir}${newPathName}"
        if [ "${testMode}" = "no" ] ; then
            mkdir --parents "${paramDestDir}${newPathName}"
        fi
    fi

    log 4 "== copying file from ${paramFromDir}${paramFile} to ${paramDestDir}${newFileName}"
    if [ -f "${paramDestDir}${newFileName}" ] ; then
        log 4 "!! cannot copy file to ${paramDestDir}${newFileName} because it already exists"
    elif [ "${testMode}" = "no" ] ; then
        cp "${paramFromDir}${paramFile}" "${paramDestDir}${newFileName}"
    fi
}

# getting parameters value
while [ $# -ge 1 ] ; do
    case "$1" in
        -h|--help) # display help
            displayHelp
            exit 0
            ;;
        -f) # set path/to/dir/ directory where the data come from
            shiftStep=2
            fromDir="${2}"
            ;;
        -d) # set path/to/dir/ directory where the data are copied
            shiftStep=2
            destDir="${2}"
            ;;
        -fr) # set regex to exclude some item from being copied
            shiftStep=2
            fromDirExcludeRegex="${2}"
            ;;
        -dr) # set regex to exclude some item from being deleted from the destination directory
            shiftStep=2
            destDirExcludeRegex="${2}"
            ;;
        -k) # keep data on destination directory
            shiftStep=1
            keepFiles="yes"
            ;;
        -s) # set the maximum size of the destination directory
            shiftStep=2
            maxSize="${2}"
            ;;
        -ll) # set the log level
            shiftStep=2
            logLevel="${2}"
            ;;
        -lf) # set the log file
            shiftStep=2
            logFile="${2}"
            ;;
        -c) # enable fat 32 compatible mode
            shiftStep=1
            fat32CompatibleMode="yes"
            ;;
        -t) # enable test mode
            shiftStep=1
            testMode="yes"
            ;;
        *)
            displayUsage
            exit 1
            ;;
    esac

    if [ $# -ge "$shiftStep" ] ; then
        shift "${shiftStep}"
    else
        log 1 "invalid number of arguments"
        exit 2
    fi
done

# setting parameters value
: ${fromDir:="${defaultFromDir}"}
: ${destDir:="${defaultDestDir}"}
: ${keepFiles:="${defaultKeepFiles}"}
: ${maxSize:="${defaultMaxSize}"}
: ${logLevel:="${defaultLogLevel}"}
: ${logFile:="${defaultLogFile}"}
: ${fat32CompatibleMode:="${defaultFat32CompatibleMode}"}
: ${testMode:="${defaultTestMode}"}

# checking parameters value
if [ ! -d "$(dirname "${logFile}")" ] ; then
    log 1 "$(dirname "${logFile}") does not exist"
    exit 3
fi

if [ ! -d "${fromDir}" ] ; then
    log 1 "${fromDir} does not exist"
    exit 4
fi

if [ ! -d "${destDir}" ] ; then
    log 1 "${destDir} does not exist"
    exit 5
fi

# script
RANDOM=$(head -1 /dev/urandom | od -N 1 | awk '{print $2}')

if [ "$keepFiles" = "no" ] ; then
    log 2 "- deleting files on the player"
    if [ "${testMode}" = "no" ] ; then
        find "$destDir" -depth -mindepth 1 -not -regex "${defaultDestDirExcludeRegex}" -delete
    fi
fi

while true
do
    getRandomDir "${fromDir}"
    randomDirSize="$(du -sk "${randomDir}" | awk '{print $1}')"
    destDirSize="$(du -sk "${destDir}" | awk '{print $1}')"
    destDirFreeSpace="$(df -k "${destDir}" | tail -1 | awk '{print $4}')"

    if [ "${randomDirSize}" -gt "${destDirFreeSpace}" ] ; then
        log 2 "! cannot copy ${randomDir} (${randomDirSize} ko) on ${destDir} because there is not enough free space (${destDirFreeSpace} ko)"
        break
    elif [ -n "${maxSize}" ] && [ "$(( ${randomDirSize} + ${destDirSize} ))" -gt "${maxSize}" ] ; then
        log 2 "! cannot copy ${randomDir} (${randomDirSize} ko) on ${destDir} because ${destDir} would exceed the maximum size parameter (${maxSize} ko)"
        break
    else
        copyDir "${randomDir}" "${destDir}" "${defaultFromDirExcludeRegex}"
    fi
done

log 2 ". syncing filesystem"
sync
log 1 ". filesystem has been synced and is now consistent"

Dernière modification par ploc (Le 10/06/2008, à 22:30)

Hors ligne

#5 Le 23/04/2008, à 15:02

ploc

Re : [résolu] script bash de copie de répertoires aléatoirement choisis

Une version 0.2 vient de corriger quelques soucis de jeunesse...

Hors ligne

#6 Le 01/05/2008, à 18:17

ploc

Re : [résolu] script bash de copie de répertoires aléatoirement choisis

Une version 0.3 vient améliorer un peu le script (permet entre autre de sélectionner un niveau de log).

Hors ligne

#7 Le 02/05/2008, à 12:20

ploc

Re : [résolu] script bash de copie de répertoires aléatoirement choisis

Une version 0.4 vient améliorer la qualité globale du code...

Hors ligne

#8 Le 20/05/2008, à 22:31

ploc

Re : [résolu] script bash de copie de répertoires aléatoirement choisis

Une version 0.5 est commentée et gère les noms de fichiers à la mode fat32...

Hors ligne

#9 Le 09/06/2008, à 14:15

ploc

Re : [résolu] script bash de copie de répertoires aléatoirement choisis

En fait, j'aurais peut-être eu plus de contribution si j'avais présenté les choses autrement :

En fait, je voulais faire l'équivalent du lecteur Apple Ipod Shuffle couplé avec le logiciel Itunes.

Ce script bash, permet de faire l'équivalent, sans Ipod et sans Itunes. Il permet donc de sélectionner aléatoirement des albums dans votre collection de musique pour les copier sur votre lecteur portable de musique.

Bonne musique à vous !

Hors ligne

#10 Le 10/06/2008, à 15:03

Saito

Re : [résolu] script bash de copie de répertoires aléatoirement choisis

Salut,

j'ai regardé rapidement ton script et j'ai quelques petites choses à dire:
- ta fonction displayHelp peut être améliorée en utilisant un here-doc plutôt que d'utiliser de multiples echo (plus clair, pas besoin d'échapper quoi que ce soit)

displayHelp () {
cat <<EOF
$(basename "$0") fills a directory randomly picking directories from another directory.
  
It can either stop processing when the destination directory is full or when the destination directory reaches a maximum size parameter. It can also remove any file in the destination directory before processing.
A test mode is available that does not copy any file (beware of infinite loop).
EOF
    displayUsage
cat <<EOF
Available optionnal parameters are :
    -h  - display help
    -f  - set path/to/dir/ directory where the data come from
    -d  - set path/to/dir/ directory where the data are copied
    -fr - set regex to exclude some item from being copied
    -dr - set regex to exclude some item from being deleted from the destination directory (useless if -k is set)
    -k  - keep data on destination directory (otherwise destination directory will be emptied)
    -s  - set the maximum size of the destination directory (in ko)
    -ll - set the log level
    -lf - set the log file
    -c  - enable fat 32 compatible mode
    -t  - enable test mode (nothing is copied neither deleted)
EOF
}

Bien sûr, cela implique que le système possède cat, mais sur Ubuntu ça devrait aller.

- Question de goût et de lisibilité mais tu peux raccourcir :

if [ -z "${maxSize}" ] ; then
    maxSize="${defaultMaxSize}"
fi

en

: ${maxSize:=$defaultMaxSize}

- pourquoi créer $RANDOM alors qu'il existe déjà?

Sinon, le script est bien fait smile

Dernière modification par Saito (Le 10/06/2008, à 15:32)


Aku-Soku-Zan_Shinsengumi

Hors ligne

#11 Le 10/06/2008, à 22:25

ploc

Re : [résolu] script bash de copie de répertoires aléatoirement choisis

Merci Saito de tes remarques.

J'ai tiré parti de tes remarques pour améliorer le script selon tes conseils. La version 0.6 est maintenant disponible.

Tes astuces fonctionnent, mais j'aime comprendre ce que je fais. C'est pourquoi j'apprécierais que tu apportes un complément d'information : pourquoi faut-il commencer les lignes suivantes par un : (deux points) ?

: ${maxSize:=$defaultMaxSize}

D'autre part, $RANDOM existe déjà, existe toujours d'ailleurs, mais je l'initialise à une valeur aléatoire afin de rendre la fonction plus aléatoire. Je fais ce qu'on appelle planter une graine aléatoire, on appelle donc cela seed (graine, en Anglais). Je me suis un peu penché sur le sujet et il apparaît qu'il est très difficile pour un ordinateur de générer une suite de nom réellement aléatoire. Le fait d'utiliser une graine comme je le fais rend la fonction $RANDOM une peu plus aléatoire (mais toujours pas parfaite).

Merci en tout cas de ton intervention.

Dernière modification par ploc (Le 10/06/2008, à 22:32)

Hors ligne

#12 Le 12/06/2008, à 16:11

Saito

Re : [résolu] script bash de copie de répertoires aléatoirement choisis

Alors, en ce qui concerne

: ${maxSize:=$defaultMaxSize}

les «:» sont obligatoires car sinon ${x:=$y} est développé (cette forme renvoit la valeur de $x si elle n'est pas vide, sinon initialise $x à la valeur de $y et renvoie $y)  et, étant placé en première position, sera considéré comme une commande.
Tu peux le voir comme ceci:

bob@ayane:~$ ${a:=2} && echo $a
bash: 2: command not found 
// $a étant vide, ${a:=2} est développé en 2 (tout en l'assignant à $a) or 2 n'est pas une commande
bob@ayane:~$ : ${a:=2} && echo $a
2
bob@ayane:~$

Le manuel de bash explique trés bien l'action de la commande «:»:

Sans  effet ; cette commande ne fait rien d’autre que développer
les arguments et effectuer toute redirection spécifiée.

On a ici un test et une assignation implicite qui nécessite de développer l'argument, c'est pour ça qu'on utilise cette commande no-op.

Pour $RANDOM, je suis d'accord avec toi sur le seed, l'effet sera sans doute meilleur.

Dernière modification par Saito (Le 12/06/2008, à 16:24)


Aku-Soku-Zan_Shinsengumi

Hors ligne