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 08/08/2017, à 21:09

kholo

[TUTO Bash] rangement automatique fichiers par extension

Bonjour à tous,
Voici un script pour organiser des fichiers selon l'extension ou leur type mime
edit du 2020 05 22 : je me rend compte que j'avais laissé pas mal de coquilles alors je vais donner sa chance à mon script en les corrigeant et en le mettant un peu au goût du jour et de mes connaissances !

C'est l'utilisateur qui va choisir le nom du dossier avec lequel chaque extension sera associée.
voici une vidéo de l'utilisation : une vidéo de démonstration

Dorian (je l'ai appelé ainsi) va nous aider à ranger des fichiers contenus dans un dossier
son principe de fonctionnement repose sur les extensions des fichiers.

En fonction de l'extension, Dorian se baser sur une base personnelle et créera un dossier pour y déplacer le fichier
l'association entre extension et nom de dossir pourra choisir lors de la première découverte de l'extension et modifiée par la suite.

Si le fichier ne comporte pas d'extension Dorian se contente de le ranger par Type Mime et
créera donc des dossiers et sous dossiers en fonction des types Mime trouvés

PARTIE 1
le script principal dorian
créez un dossier

mkdir -p $HOME/bin

créez un fichier

touch $HOME/bin/dorian

le rendre exécutable

chmod +x $HOME/bin/dorian

éditer avec

gedit $HOME/bin/dorian

et copier le texte suivant

#!/bin/bash
# nautilus "${PWD}" ; exit 0

#**************************************************************************
NOM_LOGICIEL="${0##*/}"
FONCTION="Dorian...
va nous aider à ranger des fichiers contenus dans un dossier
son principe de fonctionnement repose sur les extensions de fichier.

En fonction de l'extension, Dorian va alimenter une base personnelle et créera un dossier 
que chacun pourra choisir lors de la première découverte de l'extension.

Si le fichier ne comporte pas d'extension Dorian se contente de le ranger par Type Mime et 
créera donc des dossiers et sous dossiers en fonction des types Mime trouvés
"
VERSION="0.007"
#NOTES DE VERSIONS
#----------------------------------------------
#
# 0.007
# [ VS [[ à voir !
# 0.006
# nettoyage
# 0.005
# suppression des "function" 
# 0.004
# premiers tests et mises au point des fonctions
#----------------------------------------------
#echo "lancement ${NOM_LOGICIEL}..."

# zenity --info --text "${@}"
# exit 0

#**************************************************************************

#INITIALISATION DES VARIABLES

#durée d'exécution pour horodatage du log
START=$(date +%s.%N)

#DIR_CONF
DIR_CONF="${HOME}/.config/kholo/${NOM_LOGICIEL}"
# Création du dossier si il n'existe pas
[ -d "${DIR_CONF}" ] || mkdir -p "${DIR_CONF}"

FICHIER_LOG="${DIR_CONF}/${NOM_LOGICIEL}.log"

FILE_EXT_CONNUES="${DIR_CONF}/extConnues.txt"
# Création du fichier si il n'existe pas
[ -f "${FILE_EXT_CONNUES}" ] || > "${FILE_EXT_CONNUES}"

#DIR_ORIG
DIR_ORIG=""

#DIR_DEST
DIR_DEST=""

LES_EXT_CONNUES=()
LES_NOMS_DOSSIERS=()

#**************************************************************************

#ETAGE JOURNAL
_journal () {
	#journal cumulé
	[ -f "${FICHIER_LOG}" ] || > "${FICHIER_LOG}"

	#on vide le log ou on le crée si il n'existe pas
	# > "${FICHIER_LOG}"

	journal "ouverture - $(date)"
	journal "Ligne ${LINENO}--\t\t------------------------"
	}
journal () {
	local NOW=$(date +%s.%N)
	local DIFF=$(echo "${NOW} - ${START}" | bc)
	echo -e "[${DIFF}] ${@}" >> "${FICHIER_LOG}"
	}
_journal

journal "Ligne ${LINENO}--\t\t\tchargement"
#**************************************************************************

#CHARGEMENT DES BASES
nettoyerFichier () {
	journal "Ligne ${LINENO}--\t\t-> ${FUNCNAME[0]}"
	# journal "Ligne ${LINENO}--\t\tArguments -> ${@}"

	#range les lignes d'un fichier dans l'ordre alphabétique
	sort -d -f -b -u "${@}" | tee "${@}.new" && mv "${@}.new" "${@}"

	#supprime les lignes vides d'un fichier
	sed -i '/^$/d' "${@}"
	}
chargerEXT_CONNUES () {
	journal "Ligne ${LINENO}--\t\t-> ${FUNCNAME[0]}"
	# journal "Ligne ${LINENO}--\t\tArguments -> ${@}"
	#Initialisation des bases
	LES_EXT_CONNUES=()
	LES_NOMS_DOSSIERS=()
	#Chargement des bases
	local LIGNE
	for LIGNE in $(cat "${FILE_EXT_CONNUES}")
	do
		LES_EXT_CONNUES+=( ${LIGNE%%;*} )
		LES_NOMS_DOSSIERS+=( ${LIGNE##*;} )
	done
	}

nettoyerFichier "$FILE_EXT_CONNUES" >/dev/null
chargerEXT_CONNUES

journal "Ligne ${LINENO}--\t\tchargement"
#**************************************************************************

#Rangement par type Mine en cas de manque d'extension
getTYPE_MIME_FICHIER () {
	journal "Ligne ${LINENO}--\t\t-> ${FUNCNAME[0]}"
	# journal "Ligne ${LINENO}--\t\tArguments -> ${@}"
	local CHEMIN_FICHIER="$1"

	local LE_TYPE_MIME="$(file -b -i "${CHEMIN_FICHIER}")"
	if [ $? -eq 1 ]
	then 
		journal "Ligne ${LINENO}--\t\t------------\nPROBLEME : \n${PWD} \n${CHEMIN_FICHIER} \n${LE_TYPE_MIME}\n-------------"
	else
		journal "Ligne ${LINENO}--\t\t${CHEMIN_FICHIER} \n->${LE_TYPE_MIME}" 
		TYPE_MIME_partie1="${LE_TYPE_MIME%%; *}"
		echo "${TYPE_MIME_partie1}"
	fi
	journal "Ligne ${LINENO}--\t\tfin du découpage TYPE_MIME"
	}
rangerFichierParTypeMime () {
	journal "Ligne ${LINENO}--\t\t-> ${FUNCNAME[0]}"
	# journal "Ligne ${LINENO}--\t\tArguments -> ${@}"
	local CHEMIN_FICHIER="${@}"
	local LE_DOSSIER="0_$(getTYPE_MIME_FICHIER "${@}" 1)"
	journal "Ligne ${LINENO}--\t\tdéplacement de \n${CHEMIN_FICHIER} \nvers \n${DIR_DEST}/${LE_DOSSIER}"
	deplacerFichier "${CHEMIN_FICHIER}" "${DIR_DEST}/${LE_DOSSIER}"
	}
journal "Ligne ${LINENO}--\t\tchargement"
#**************************************************************************
deplacerFichier () {
	journal "Ligne ${LINENO}--\t\t-> ${FUNCNAME[0]}"
	# journal "Ligne ${LINENO}--\t\tArguments -> ${@}"
	local unFichier
	local uneDestination
	unFichier="${1}"
	uneDestination="${2}"
	journal "Ligne ${LINENO}--\t\tunFichier : ${unFichier}"
	journal "Ligne ${LINENO}--\t\tuneDestination : ${uneDestination}/"
	[ -d "${uneDestination}" ] || mkdir -p "${uneDestination}" && \
		journal "Ligne ${LINENO}--\t\tcréation dossier ${uneDestination} réussie"
	mv "${unFichier}" "${uneDestination}/" && \
		journal "Ligne ${LINENO}--\t\tdéplacement réussi" || \
		journal "Ligne ${LINENO}--\t\tdéplacement échec"
	}

journal "Ligne ${LINENO}--\t\tchargement"
#**************************************************************************

#ETAGE TRAITEMENT SELON EXTENSION
frm_EntryChoixType () {
	journal "Ligne ${LINENO}--\t\t-> ${FUNCNAME[0]}"
	# journal "Ligne ${LINENO}--\t\tArguments -> ${@}"
	zenity --entry \
		--title="Choisir un type" \
		--text="l'extension ${@} n'a pas été trouvée ; \najouter aux motifs de type :" \
		--entry-text=$(echo "${LES_NOMS_DOSSIERS[@]}" | tr ' ' '\n' | sort -u)
	}
ajouterMotifExtension () {
	journal "Ligne ${LINENO}--\t\t-> ${FUNCNAME[0]}"
	# journal "Ligne ${LINENO}--\t\tArguments -> ${@}"

	Nouveau_Dossier="$(frm_EntryChoixType "${1}")"
	# if [ ${#Nouveau_Dossier} -gt 0 ] 
	# then
		journal "Ligne ${LINENO}--\t\t# Ajouter aux extensions connues ${@};${Nouveau_Dossier}"
		if [ ${#@} -ne 0 ] && [ ${#Nouveau_Dossier} -ne 0 ]
		then
			echo "${@};${Nouveau_Dossier}" | tee -a "${FILE_EXT_CONNUES}"

			LES_EXT_CONNUES+=( ${@} )
			LES_NOMS_DOSSIERS+=( ${Nouveau_Dossier} )

		else
			return 1
		fi
	# else
		journal "Ligne ${LINENO}--\t\tnewMotifExt = ${Nouveau_Dossier}" # TODO ?
		# return 1
	# fi
	}
chercherExtdansDB () {
	journal "Ligne ${LINENO}--\t\t-> ${FUNCNAME[0]}"
	# journal "Ligne ${LINENO}--\t\tArguments -> ${@}"

	# recherche dans les extensions connues 
	# renvoie un dossier si trouvé sinon rien 
	local leTest="${@}" # c'est l'extension à tester
	journal "Ligne ${LINENO}--\t\t#LES_EXT_CONNUES : ${#LES_EXT_CONNUES[@]}"
	for (( c=0;c<${#LES_EXT_CONNUES[@]};c++ ))
	do
		# journal "Ligne ${LINENO}--\t\t${leTest} == ${LES_EXT_CONNUES[$c]} ?"
		if [[ "${leTest}" == "${LES_EXT_CONNUES[$c]}" ]] 
		then
			journal "Ligne ${LINENO}--\t\tOUI extension trouvée : ${LES_NOMS_DOSSIERS[$c]}"
			echo "${LES_NOMS_DOSSIERS[$c]}"
			break
		# else
			# journal "Ligne ${LINENO}--\t\tNON"
		fi
	done
	}
rangerFichiersParExtension () {
	journal "Ligne ${LINENO}--\t\t-> ${FUNCNAME[0]}"
	# journal "Ligne ${LINENO}--\t\tArguments -> ${@}"
	CHEMIN_FICHIER="${@}" ;
	NOM_FICHIER="${CHEMIN_FICHIER##*/}"
	EXT_FICHIER="${NOM_FICHIER##*.}"

	local leCHEMIN="$(chercherExtdansDB "${EXT_FICHIER}")"
	journal "Ligne ${LINENO}--\t\tleCHEMIN : ${leCHEMIN}"

	if [ "${#leCHEMIN}" -eq 0 ] 
	then
		journal "Ligne ${LINENO}--\t\textension inconnue"
		local NOUVEAU_DOSSIER="$(ajouterMotifExtension "${EXT_FICHIER}")"
		if [ ! ${#NOUVEAU_DOSSIER} -eq 0 ] 
		then
			NOUVEAU_DOSSIER="${NOUVEAU_DOSSIER##*;}"
			deplacerFichier "${CHEMIN_FICHIER}" "${DIR_DEST}/${NOUVEAU_DOSSIER}"
			nettoyerFichier "$FILE_EXT_CONNUES" >/dev/null
			chargerEXT_CONNUES
		else
			journal "Ligne ${LINENO}--\t\tl'extension ne sera pas ajoutée"
		fi
	else
		journal "Ligne ${LINENO}--\t\tDéplacement du fichier selon extension"
		deplacerFichier "${CHEMIN_FICHIER}" "${DIR_DEST}/${leCHEMIN[$c]}"
	fi
	}
traiterFichier () {
	journal "Ligne ${LINENO}--\t\t----------------------------------"
	journal "Ligne ${LINENO}--\t\t-> ${FUNCNAME[0]}"
	# journal "Ligne ${LINENO}--\t\tArguments -> ${@}"
	CHEMIN_FICHIER="$(readlink -f "${@}")"
	NOM_FICHIER="${CHEMIN_FICHIER##*/}"
	EXT_FICHIER="${NOM_FICHIER##*.}"
	if [ "${EXT_FICHIER}" == "${NOM_FICHIER}" ]
	then
		journal "Ligne ${LINENO}--\t\t-------------pas d'extension !-------------"
		rangerFichierParTypeMime "${CHEMIN_FICHIER}"
	else 
		journal "Ligne ${LINENO}--\t\tl'extension est ${EXT_FICHIER}"
		rangerFichiersParExtension "${CHEMIN_FICHIER}"
	fi
	}

journal "Ligne ${LINENO}--\t\tchargement"
#**************************************************************************

#Etage traitement des arguments du script
setDIR_DEST () {
	journal "Ligne ${LINENO}--\t\t-> ${FUNCNAME[0]}"
	# journal "Ligne ${LINENO}--\t\tArguments -> ${@}"
	DIR_DEST="${DIR_ORIG}"
	}
estLienDossierFichier () {
	journal "Ligne ${LINENO}--\t\t-> ${FUNCNAME[0]}"
	# journal "Ligne ${LINENO}--\t\tArguments -> ${@}"
	if [ -L "${@}" ]
	then 
		journal "error : $@ est un lien"
	else
		if [ -d "${@}" ]
		then 
			journal "error : $@ est un dossier"
		else
			if [ -f "${@}" ]
			then 
				# DIR_ORIG="${@}"
				DIR_ORIG="${@%/*}"
				setDIR_DEST
				traiterFichier "${@}"
			fi
		fi
	fi
	}
traiterLesArguments () {
	journal "Ligne ${LINENO}--\t\t-> ${FUNCNAME[0]}"
	# journal "Ligne ${LINENO}--\t\tArguments -> ${@}"
	IFS=$'\n'
	local url
	for url in $@
	do
		journal "---------------------------------------------"
		journal "Ligne ${LINENO}--\t\turl : ${url}"
		estLienDossierFichier "${url}"
	done
	}

selectionnerTousLesFichiers () {
	journal "Ligne ${LINENO}--\t\t-> ${FUNCNAME[0]}"
	for FILE in *
	do
		if [ -e "$(readlink -f "${FILE}")" ] 
		then
			estLienDossierFichier "$(readlink -f "${FILE}")"
		else
			journal "erreur avec ${FILE}"
		fi
	done
	}
afficher_ExtConnues () {
	journal "Ligne ${LINENO}--\t\t-> ${FUNCNAME[0]}"
	cat "${FILE_EXT_CONNUES}"
	echo -e "le fichier est : ${FILE_EXT_CONNUES}"
	exit  66
	}
afficher_fichier_log () {
	cat "${FICHIER_LOG}"
	echo -e "le fichier est : ${FICHIER_LOG}"
	exit  67
	}
vider_fichier_log () {
	>"${FICHIER_LOG}"
	echo -e "le fichier est vidé : \n${FICHIER_LOG}"
	exit  67
	}
afficher_aide () {
cat <<EOF 
dorian va nous aider à ranger nos fichiers
lancez dorian [Ff:hHvVcl]

dorian -h ou -H 
	cette aide
dorian -v ou -V 
	la version de ce script
dorian -F 
	range tous les fichiers trouvés dans le répertoire courant
dorian -f  'un Fichier'
	range 'un Fichier' mettre -f pour chaque fichier
dorian "/un/fichier/ici" "/un/fichier/la"
	liste de fichiers séparés par des sauts de ligne ou des espaces
dorian -c 
	affiche le fichier des extentions de l'utilisateur courant et son emplacement.
dorian -l 
	affiche le fichier log de l'utilisateur courant et son emplacement.
EOF
	afficher_version
	}
afficher_version () {
	echo "$0 version : $VERSION"
	}
traiterLesOptions () {
	journal "Ligne ${LINENO}--\t\t-> ${FUNCNAME[0]}"
	while getopts cFf:hHlvV option # : pour dire que l'option attend un argument
	do
		case "${option}" in
			c ) afficher_ExtConnues ;;
			F ) selectionnerTousLesFichiers ;;
			f ) [ -e "$(readlink -f "${OPTARG}")" ] && estLienDossierFichier "$(readlink -f "${OPTARG}")" ;;
			h | H ) afficher_aide ;;
			l ) afficher_fichier_log ;;
			L ) vider_fichier_log ;;
			v | V ) afficher_version ;;

		esac
	done
	shift $(($OPTIND-1))

	[ -n $1 ] && journal "Ligne ${LINENO}--\t\tje n'ai pas traité cela : ${@}"
	}
voirArguments () {
	journal "Ligne ${LINENO}--\t\t-> ${FUNCNAME[0]}"
	if [ ! ${#@} -eq 0 ] 
	then
		journal "Ligne ${LINENO}--\t\tNbre d'arguments trouvés : ${#@}"
		case $@ in
			-* ) traiterLesOptions "$@" ;;
			*) traiterLesArguments "$@" ;;
		esac
	else
		journal "Ligne ${LINENO}--\t\tpas d'arguments trouvés"
		afficher_aide
		echo "erreur 65 ; arguments manquants"
		exit 65
	fi
	}

journal "Ligne ${LINENO}--\t\tchargement"
#**************************************************************************

# nautilus "${PWD}"
# nautilus "$HOME/.config/kholo/dorian"
# exit 0

IFS=$'\n'
voirArguments $@

journal "---------------------------------------------
Ligne ${LINENO}--\t\tfermeture"
#**************************************************************************

exit 0

PARTIE 2
un lanceur pour nautilus (à adapter si vous avez choisi un autre dossier que $HOME/bin)

touch $HOME/.local/share/nautilus/scripts/dorian

le rendre exécutable

chmod +x $HOME/.local/share/nautilus/scripts/dorian

puis on l'édite

gedit $HOME/.local/share/nautilus/scripts/dorian

et copiez le code suivant
sa seule fonction est d'envoyer la liste des fichiers sélectionnés au script qui pourra donc être facilement adapté pour la LdC ou un autre gestionnaire de fichiers

#!/bin/bash
IFS=$'\n'
leCHEMIN="$HOME/bin/dorian"
"${leCHEMIN}" $NAUTILUS_SCRIPT_SELECTED_FILE_PATHS

PARTIE 3
maintenant un fichier pour éditer les associations entre extensions et noms de dossier
on va créer un dossier spécifique

mkdir -p "$HOME/.config/kholo/dorian"

et un fichier de configuration à y mettre
exemple de fichier de configuration (facilement adaptable) :
extension puis point virgule puis nom de dossier
exemple : bin;programmes => les bin iront dans le dossier programmes
plusieurs extensions peuvent aller dans le même dossier mais si une même extension est plusieurs fois, seule la première sera prise en considération
(il faut que je vérifie... et surtout que je mette une routine pour faire du nettoyage si cela arrive... encore que ce ne puisse arriver que si une édition est faite à la main !)
NB ce fichier est mis à jour automatiquement chaque fois que vous ajoutez des extensions durant un rangement

gedit "$HOME/.config/kholo/dorian/extConnues.txt"
bin;programmes
bz2;compression
conf;scripts
db;bases
deb;scripts
doc;bureautique
exe;programmes
gif;images
gz;compression
html;texte
jp2;images
jpeg;photos
mid;musique
ods;bureautique
odt;bureautique
pdf;bureautique
php;scripts
png;images
py;scripts
sh;scripts
sql;bases
tgz;compression
txt;texte
xlsx;bureautique
xz;compression
zip;compression

PARTIE 4 : Utilisation
maintenant allez dans un dossier et sélectionnez des fichiers
puis clic droit / scripts / dorian
et, donnez un nom pour le dossier chaque fois qu'une extension inconnue est trouvée
chaque fichier dont l'extension est identique sera rangé avec ses congénères
les fichiers sans extensions seront rangés par type mime dans un dossier commençant par 0type/nomdutype

Dernière modification par kholo (Le 22/05/2020, à 13:34)

Hors ligne

#2 Le 19/08/2017, à 10:53

kholo

Re : [TUTO Bash] rangement automatique fichiers par extension

édit du 22 mai 2020...
comme j'ai mis la version 007 dans le premier post, je modifie rapidement le script ici... et je reviendrai mettre une version plus sympa...
je nettoie rapidement le code avant de le faire évoluer autant dans son comportement que dans certaines lourdeurs
=> le journal est tenu dans le dossier /tmp (que je met en RAM ce qui est mieux pour les ssd)


édit du 25 mai 2020...
je vire ma version du 22 et met une version 009 corrigée avec les préconisations de Watael... j'ai suivi la quasi totalité des conseils...
je répond dans un post au point par point dans la suite de ce fil...

#!/bin/bash

# nautilus "${PWD}" ; exit 0

#**************************************************************************
nom_logiciel="${0##*/}"
fonction_logiciel="Dorian...
va nous aider à ranger des fichiers contenus dans un dossier
son principe de fonctionnement repose sur les extensions de fichier.

En fonction de l'extension, Dorian va alimenter une base personnelle et créera un dossier 
que chacun pourra choisir lors de la première découverte de l'extension.

Si le fichier ne comporte pas d'extension Dorian se contente de le ranger par Type Mime et 
créera donc des dossiers et sous dossiers en fonction des types Mime trouvés
"
version_logiciel="0.009"
#NOTES DE VERSIONS
#----------------------------------------------
# 0.009 corrections suite aux observations, conseils et préconisations de Watael
# https://forum.ubuntu-fr.org/viewtopic.php?pid=22289390#p22289390
# 0.008
# nettoyage rapide 2020
# 0.007
# [ VS [[ à voir !
# 0.006
# nettoyage
# 0.005
# suppression des "function" 
# 0.004
# premiers tests et mises au point des fonctions
#----------------------------------------------
#echo "lancement ${nom_logiciel}..."

# zenity --info --text "${@}"
# exit 0

#**************************************************************************

#INITIALISATION DES VARIABLES

#durée d'exécution pour horodatage du log
debut=$(date +%s.%N)

#dossier_conf
dossier_conf="${HOME}/.config/kholo/${nom_logiciel}"
## Création du dossier si il n'existe pas
[ -d "${dossier_conf}" ] || mkdir -p "${dossier_conf}"

## je met tmp en ram donc je vais m'en servir pour log plus vite
# fichier_log="${dossier_conf}/${nom_logiciel}.log"
fichier_log="/tmp/${nom_logiciel}.log"
## et une ligne à la fin pour déplacer le log à la bonne place


file_ext_connues="${dossier_conf}/extConnues.txt"
## Création du fichier si il n'existe pas
[ -f "${file_ext_connues}" ] || > "${file_ext_connues}"

#dossier_orig
dossier_orig=""

#dossier_dest
dossier_dest=""

les_ext_connues=()
les_noms_dossiers=()

#**************************************************************************

#ETAGE JOURNAL
journal () {
    local maintenant=$(date +%s.%N)
    local difference=$(echo "${maintenant} - ${debut}" | bc)
    echo -e "[${difference}] ${@}" >> "${fichier_log}"
}
#journal cumulé
[ -f "${fichier_log}" ] || > "${fichier_log}"

#on vide le log ou on le crée si il n'existe pas
# > "${fichier_log}"

journal "ouverture - $(date)"
journal "Ligne ${LINENO}--\t\t------------------------"

journal "Ligne ${LINENO}--\t\t\tchargement"
#**************************************************************************

#CHARGEMENT DES BASES
nettoyerFichier () {
    journal "Ligne ${LINENO}--\t\t-> ${FUNCNAME[0]}"
    # journal "Ligne ${LINENO}--\t\tArguments -> ${@}"

    #range les lignes d'un fichier dans l'ordre alphabétique
    sort -d -f -b -u "${@}" | tee "${@}.new" && mv "${@}.new" "${@}"

    #supprime les lignes vides d'un fichier
    sed -i '/^$/d' "${@}"
}
charger_ext_connues () {
    journal "Ligne ${LINENO}--\t\t-> ${FUNCNAME[0]}"
    # journal "Ligne ${LINENO}--\t\tArguments -> ${@}"
    #Initialisation des bases
    les_ext_connues=()
    les_noms_dossiers=()
    #Chargement des bases
    local une_ligne
    while IFS= read -r une_ligne
    do
        les_ext_connues+=( ${une_ligne%%;*} )
        les_noms_dossiers+=( ${une_ligne##*;} )
    done < "${file_ext_connues}"
}

nettoyerFichier "$file_ext_connues" >/dev/null
charger_ext_connues

journal "Ligne ${LINENO}--\t\tchargement"
#**************************************************************************

#Rangement par type Mine en cas de manque d'extension
getTYPE_MIME_FICHIER () {
    journal "Ligne ${LINENO}--\t\t-> ${FUNCNAME[0]}"
    # journal "Ligne ${LINENO}--\t\tArguments -> ${@}"
    local chemin_fichier="$1"

    local le_type_mime="$(file -b -i "${chemin_fichier}")"
    if [ $? -eq 1 ]
    then 
        journal "Ligne ${LINENO}--\t\t------------\nPROBLEME : \n${PWD} \n${chemin_fichier} \n${le_type_mime}\n-------------"
    else
        journal "Ligne ${LINENO}--\t\t${chemin_fichier} \n->${le_type_mime}" 
        type_mime_partie1="${le_type_mime%%; *}"
        echo "${type_mime_partie1}"
    fi
    journal "Ligne ${LINENO}--\t\tfin du découpage TYPE_MIME"
}
rangerFichierParTypeMime () {
    journal "Ligne ${LINENO}--\t\t-> ${FUNCNAME[0]}"
    # journal "Ligne ${LINENO}--\t\tArguments -> ${@}"
    local chemin_fichier="${@}"
    local le_dossier="0_$(getTYPE_MIME_FICHIER "${@}" 1)"
    journal "Ligne ${LINENO}--\t\tdéplacement de \n${chemin_fichier} \nvers \n${dossier_dest}/${le_dossier}"
    deplacerFichier "${chemin_fichier}" "${dossier_dest}/${le_dossier}"
}
journal "Ligne ${LINENO}--\t\tchargement"
#**************************************************************************
deplacerFichier () {
    journal "Ligne ${LINENO}--\t\t-> ${FUNCNAME[0]}"
    # journal "Ligne ${LINENO}--\t\tArguments -> ${@}"
    local unFichier
    local uneDestination
    unFichier="${1}"
    uneDestination="${2}"
    journal "Ligne ${LINENO}--\t\tunFichier : ${unFichier}"
    journal "Ligne ${LINENO}--\t\tuneDestination : ${uneDestination}/"
    [ -d "${uneDestination}" ] || mkdir -p "${uneDestination}" && \
        journal "Ligne ${LINENO}--\t\tcréation dossier ${uneDestination} réussie"
    mv "${unFichier}" "${uneDestination}/" && \
        journal "Ligne ${LINENO}--\t\tdéplacement réussi" || \
        journal "Ligne ${LINENO}--\t\tdéplacement échec"
}

journal "Ligne ${LINENO}--\t\tchargement"
#**************************************************************************

#ETAGE TRAITEMENT SELON EXTENSION
frm_EntryChoixType () {
    journal "Ligne ${LINENO}--\t\t-> ${FUNCNAME[0]}"
    # journal "Ligne ${LINENO}--\t\tArguments -> ${@}"
    zenity --entry \
        --title="Choisir un type" \
        --text="l'extension ${@} n'a pas été trouvée ; \najouter aux motifs de type :" \
        --entry-text=$(echo "${les_noms_dossiers[@]}" | tr ' ' '\n' | sort -u)
}
ajouterMotifExtension () {
    journal "Ligne ${LINENO}--\t\t-> ${FUNCNAME[0]}"
    # journal "Ligne ${LINENO}--\t\tArguments -> ${@}"

    le_nouveau_dossier="$(frm_EntryChoixType "${1}")"
    # if [ ${#le_nouveau_dossier} -gt 0 ] 
    # then
        journal "Ligne ${LINENO}--\t\t# Ajouter aux extensions connues ${@};${le_nouveau_dossier}"
        if [ ${#@} -ne 0 ] && [ ${#le_nouveau_dossier} -ne 0 ]
        then
            echo "${@};${le_nouveau_dossier}" | tee -a "${file_ext_connues}"

            les_ext_connues+=( ${@} )
            les_noms_dossiers+=( ${le_nouveau_dossier} )

        else
            return 1
        fi
    # else
        journal "Ligne ${LINENO}--\t\tnewMotifExt = ${le_nouveau_dossier}" # TODO ?
        # return 1
    # fi
}
chercherExtdansDB () {
    journal "Ligne ${LINENO}--\t\t-> ${FUNCNAME[0]}"
    # journal "Ligne ${LINENO}--\t\tArguments -> ${@}"

    # recherche dans les extensions connues 
    # renvoie un dossier si trouvé sinon rien 
    local leTest="${@}" # c'est l'extension à tester
    journal "Ligne ${LINENO}--\t\t#les_ext_connues : ${#les_ext_connues[@]}"
    for (( c=0;c<${#les_ext_connues[@]};c++ ))
    do
        # journal "Ligne ${LINENO}--\t\t${leTest} == ${les_ext_connues[$c]} ?"
        if [ "${leTest}" = "${les_ext_connues[$c]}" ]
        then
            journal "Ligne ${LINENO}--\t\tOUI extension trouvée : ${les_noms_dossiers[$c]}"
            echo "${les_noms_dossiers[$c]}"
            break
        # else
            # journal "Ligne ${LINENO}--\t\tNON"
        fi
    done
}
rangerFichiersParExtension () {
    journal "Ligne ${LINENO}--\t\t-> ${FUNCNAME[0]}"
    # journal "Ligne ${LINENO}--\t\tArguments -> ${@}"
    chemin_fichier="${@}" ;
    nom_fichier="${chemin_fichier##*/}"
    ext_fichier="${nom_fichier##*.}"

    local un_chemin="$(chercherExtdansDB "${ext_fichier}")"
    journal "Ligne ${LINENO}--\t\tun_chemin : ${un_chemin}"

    if [ "${#un_chemin}" -eq 0 ] 
    then
        journal "Ligne ${LINENO}--\t\textension inconnue"
        local un_nouveau_dossier="$(ajouterMotifExtension "${ext_fichier}")"
        if [ ! ${#un_nouveau_dossier} -eq 0 ] 
        then
            un_nouveau_dossier="${un_nouveau_dossier##*;}"
            deplacerFichier "${chemin_fichier}" "${dossier_dest}/${un_nouveau_dossier}"
            nettoyerFichier "$file_ext_connues" >/dev/null
            charger_ext_connues
        else
            journal "Ligne ${LINENO}--\t\tl'extension ne sera pas ajoutée"
        fi
    else
        journal "Ligne ${LINENO}--\t\tDéplacement du fichier selon extension"
        deplacerFichier "${chemin_fichier}" "${dossier_dest}/${un_chemin[$c]}"
    fi
}
traiterFichier () {
    journal "Ligne ${LINENO}--\t\t----------------------------------"
    journal "Ligne ${LINENO}--\t\t-> ${FUNCNAME[0]}"
    # journal "Ligne ${LINENO}--\t\tArguments -> ${@}"
    chemin_fichier="$(readlink -f "${@}")"
    nom_fichier="${chemin_fichier##*/}"
    ext_fichier="${nom_fichier##*.}"
    if [ "${ext_fichier}" = "${nom_fichier}" ]
    then
        journal "Ligne ${LINENO}--\t\t-------------pas d'extension !-------------"
        rangerFichierParTypeMime "${chemin_fichier}"
    else 
        journal "Ligne ${LINENO}--\t\tl'extension est ${ext_fichier}"
        rangerFichiersParExtension "${chemin_fichier}"
    fi
}

journal "Ligne ${LINENO}--\t\tchargement"
#**************************************************************************

#Etage traitement des arguments du script
setdossier_dest () {
    journal "Ligne ${LINENO}--\t\t-> ${FUNCNAME[0]}"
    # journal "Ligne ${LINENO}--\t\tArguments -> ${@}"
    dossier_dest="${dossier_orig}"
}
estLienDossierFichier () {
    journal "Ligne ${LINENO}--\t\t-> ${FUNCNAME[0]}"
    # journal "Ligne ${LINENO}--\t\tArguments -> ${@}"
    if [ -L "${@}" ]
    then 
        journal "error : ${@} est un lien"
    else
        if [ -d "${@}" ]
        then 
            journal "error : ${@} est un dossier"
        else
            if [ -f "${@}" ]
            then 
                # dossier_orig="${@}"
                dossier_orig="${@%/*}"
                setdossier_dest
                traiterFichier "${@}"
            fi
        fi
    fi
}
traiterLesArguments () {
    journal "Ligne ${LINENO}--\t\t-> ${FUNCNAME[0]}"
    # journal "Ligne ${LINENO}--\t\tArguments -> ${@}"
    IFS=$'\n'
    local url
    for url in ${@}
    do
        journal "---------------------------------------------"
        journal "Ligne ${LINENO}--\t\turl : ${url}"
        estLienDossierFichier "${url}"
    done
}

selectionnerTousLesFichiers () {
    journal "Ligne ${LINENO}--\t\t-> ${FUNCNAME[0]}"
    for un_fichier in *
    do
        if [ -e "$(readlink -f "${un_fichier}")" ] 
        then
            estLienDossierFichier "$(readlink -f "${un_fichier}")"
        else
            journal "erreur avec ${un_fichier}"
        fi
    done
}
afficher_ExtConnues () {
    journal "Ligne ${LINENO}--\t\t-> ${FUNCNAME[0]}"
    cat "${file_ext_connues}"
    echo -e "le fichier est : ${file_ext_connues}"
    exit  66
}
afficher_fichier_log () {
    cat "${fichier_log}"
    echo -e "le fichier est : ${fichier_log}"
    exit  67
}
vider_fichier_log () {
    >"${fichier_log}"
    echo -e "le fichier est vidé : \n${fichier_log}"
    exit  67
}
afficher_aide () {
cat <<EOF 
dorian va nous aider à ranger nos fichiers
lancez dorian [Ff:hHvVcl]

dorian -h ou -H 
    cette aide
dorian -v ou -V 
    la version de ce script
dorian -F 
    range tous les fichiers trouvés dans le répertoire courant
dorian -f  'un Fichier'
    range 'un Fichier' mettre -f pour chaque fichier
dorian "/un/fichier/ici" "/un/fichier/la"
    liste de fichiers séparés par des sauts de ligne ou des espaces
dorian -c 
    affiche le fichier des extentions de l'utilisateur courant et son emplacement.
dorian -l 
    affiche le fichier log de l'utilisateur courant et son emplacement.
EOF
    afficher_version
}
afficher_version () {
    echo "$0 version : $version_logiciel"
}
traiterLesOptions () {
    journal "Ligne ${LINENO}--\t\t-> ${FUNCNAME[0]}"
    while getopts cFf:hHlvV option # : pour dire que l'option attend un argument
    do
        case "${option}" in
            c ) afficher_ExtConnues ;;
            F ) selectionnerTousLesFichiers ;;
            f ) [ -e "$(readlink -f "${OPTARG}")" ] && estLienDossierFichier "$(readlink -f "${OPTARG}")" ;;
            h | H ) afficher_aide ;;
            l ) afficher_fichier_log ;;
            L ) vider_fichier_log ;;
            v | V ) afficher_version ;;

        esac
    done
    shift $(($OPTIND-1))

    [ -n $1 ] && journal "Ligne ${LINENO}--\t\tje n'ai pas traité cela : ${@}"
}
voirArguments () {
    journal "Ligne ${LINENO}--\t\t-> ${FUNCNAME[0]}"
    if [ ! ${#@} -eq 0 ] 
    then
        journal "Ligne ${LINENO}--\t\tNbre d'arguments trouvés : ${#@}"
        case ${@} in
            -* ) traiterLesOptions "${@}" ;;
            *) traiterLesArguments "${@}" ;;
        esac
    else
        journal "Ligne ${LINENO}--\t\tpas d'arguments trouvés"
        afficher_aide
        echo "erreur 65 ; arguments manquants"
        exit 65
    fi
}

journal "Ligne ${LINENO}--\t\tchargement"
#**************************************************************************

# nautilus "${PWD}"
# nautilus "$HOME/.config/kholo/dorian"
# exit 0

IFS=$'\n'
voirArguments ${@}

journal "---------------------------------------------
Ligne ${LINENO}--\t\tfermeture"
#**************************************************************************

## je met le log dans le dossier personnel de l’utilisateur
[ -f "${dossier_conf}/${nom_logiciel}.log" ] || touch "${dossier_conf}/${nom_logiciel}.log"
cat "${fichier_log}" >> "${dossier_conf}/${nom_logiciel}.log"

exit 0

Dernière modification par kholo (Le 25/05/2020, à 17:57)

Hors ligne

#3 Le 22/05/2020, à 13:54

kholo

Re : [TUTO Bash] rangement automatique fichiers par extension

édit du 22 mai 2020...
si vous suiviez ce fil, je met les deux premiers posts à jour...
juste à suivre les infos... façon fécomsa
je me garde ce post ci pour y mettre les autres navigateurs de fichiers plus tard...
à suivre !

Hors ligne

#4 Le 22/05/2020, à 14:28

Watael

Re : [TUTO Bash] rangement automatique fichiers par extension

salut,

les noms des variables doivent ne pas être tout en majuscules.
les accolades dans le développement de paramètres sont inutiles s'ils ne protègent pas d'une concaténation, ou n'indiquent pas une substitution. c'est pourquoi leur utilisation systématique est "nuisible".
for ligne in $(cat fichier) ->while read ligne; do : ...; done <fichier
les guillemets sont facultatifs entre double-crochets.
== est à réserver aux double-crochets.
et je n'ai pas l'impression que tu utilises de fonctionnalités avancées des double-crochets; leur emploi est alors inutile.
il faut mettre des guillemets autour de $@ pour éviter les découpage en mots et respecter le parcours des éléments d'un tableau (oui, $@ est un tableau).

et s'il y a des fichiers qui portent le même nom ?


Connected \o/
Welcome to sHell. · eval is evil.

Hors ligne

#5 Le 25/05/2020, à 20:04

kholo

Re : [TUTO Bash] rangement automatique fichiers par extension

Watael a écrit :

salut,

Bonjour Maître Jedi Watael... toujours content que tu prennes un peu de temps pour te pencher sur une de mes élucubrations !

Watael a écrit :

les noms des variables doivent ne pas être tout en majuscules.

ça ok... pas de soucis... j'ai repris... j'y reviendrais pour qu'elles soient un peu plus lisibles

Watael a écrit :

les accolades dans le développement de paramètres sont inutiles s'ils ne protègent pas d'une concaténation, ou n'indiquent pas une substitution. c'est pourquoi leur utilisation systématique est "nuisible".

là c'est plus compliqué pour moi... j'ai fait ça moi ? lol
alors attends j'essaie déjà de comprendre...
le développement de paramètres dans l'appelle d'une fonction ?
par exemple :

parametre="blabla"
ma_fonction(){
    #une fonction qui fait des trucs
    echo "je suis une fonction"
}
ma_fonction $parametre

et non pas :

ma_fonction ${parametre}

je pensais plus à l’esthétisme, la facilité de lecture voire la sécurité d'une façon générale...
mais une règle liée à la protection lors de concaténation... et que cela puisse avoir un côté "nuisible"...
... bon je vais y cogiter... je n'y ai pas touché encore...

Watael a écrit :

for ligne in $(cat fichier) ->while read ligne; do : ...; done <fichier

oui... ouiiii... j'ai quand même dû tatonner un peu et rezieuter des exemples contrairement à la lecture dans le cat que je sort plus intuitivement...
j'arrive à ça :

charger_ext_connues () {
    les_ext_connues=()
    les_noms_dossiers=()

    local une_ligne
    while IFS= read -r une_ligne
    do
        les_ext_connues+=( ${une_ligne%%;*} )
        les_noms_dossiers+=( ${une_ligne##*;} )
    done < "${file_ext_connues}"
}

mais tripoter à IFS semble masturbatoire !

    while read -r une_ligne
    do
        les_ext_connues+=( ${une_ligne%%;*} )
        les_noms_dossiers+=( ${une_ligne##*;} )
    done < "${file_ext_connues}"

par contre le -r ne me semble pas facultatif...
... et en parlant de ça, j'ai jamais pigé :

kiki@Sat-L500:~$ man read
kiki@Sat-L500:~$ info read
READ(2)                    Linux Programmer's Manual                   READ(2)

NAME
       read - read from a file descriptor

SYNOPSIS
       #include <unistd.h>

       ssize_t read(int fd, void *buf, size_t count);

DESCRIPTION
       read()  attempts to read up to count bytes from file descriptor fd into
       the buffer starting at buf.

       On files that support seeking, the read operation commences at the cur‐
       rent  file  offset, and the file offset is incremented by the number of
       bytes read.  If the current file offset is at or past the end of  file,
       no bytes are read, and read() returns zero.

       If count is zero, read() may detect the errors described below.  In the
       absence of any errors, or if read() does not check for errors, a read()
       with a count of 0 returns zero and has no other effects.

       If count is greater than SSIZE_MAX, the result is unspecified.

RETURN VALUE
       On success, the number of bytes read is returned (zero indicates end of
       file), and the file position is advanced by this number.  It is not  an
       error  if  this  number  is smaller than the number of bytes requested;
       this may happen for example because fewer bytes are actually  available
       right  now  (maybe  because we were close to end-of-file, or because we
       are reading from a pipe, or from a terminal),  or  because  read()  was
       interrupted by a signal.  See also NOTES.

       On  error,  -1  is  returned,  and errno is set appropriately.  In this
       case, it is  left  unspecified  whether  the  file  position  (if  any)
       changes.

ERRORS
       EAGAIN The  file descriptor fd refers to a file other than a socket and
              has been marked nonblocking (O_NONBLOCK),  and  the  read  would
              block.  See open(2) for further details on the O_NONBLOCK flag.

       EAGAIN or EWOULDBLOCK
              The  file  descriptor  fd refers to a socket and has been marked
              nonblocking   (O_NONBLOCK),   and   the   read   would    block.
              POSIX.1-2001  allows  either error to be returned for this case,
              and does not require these constants to have the same value,  so
              a portable application should check for both possibilities.

       EBADF  fd is not a valid file descriptor or is not open for reading.

       EFAULT buf is outside your accessible address space.

       EINTR  The  call  was interrupted by a signal before any data was read;
              see signal(7).

       EINVAL fd is attached to an object which is unsuitable for reading;  or
              the  file  was  opened  with  the  O_DIRECT flag, and either the
              address specified in buf, the value specified in count,  or  the
              current file offset is not suitably aligned.

       EINVAL fd  was  created  via  a call to timerfd_create(2) and the wrong
              size buffer was given to read(); see timerfd_create(2) for  fur‐
              ther information.

       EIO    I/O  error.  This will happen for example when the process is in
              a background process group, tries to read from  its  controlling
              terminal,  and  either it is ignoring or blocking SIGTTIN or its
              process group is orphaned.  It may also occur when  there  is  a
              low-level I/O error while reading from a disk or tape.

       EISDIR fd refers to a directory.

       Other errors may occur, depending on the object connected to fd.  POSIX
       allows a read() that is interrupted after reading some data  to  return
       -1  (with  errno set to EINTR) or to return the number of bytes already
       read.

CONFORMING TO
       SVr4, 4.3BSD, POSIX.1-2001.

NOTES
       On Linux, read() (and similar  system  calls)  will  transfer  at  most
       0x7ffff000  (2,147,479,552)  bytes, returning the number of bytes actu‐
       ally transferred.  (This is true on both 32-bit and 64-bit systems.)

       On NFS filesystems, reading small amounts of data will update the time‐
       stamp  only  the  first  time, subsequent calls may not do so.  This is
       caused by client side attribute caching, because most if  not  all  NFS
       clients  leave  st_atime (last file access time) updates to the server,
       and client side reads satisfied from the client's cache will not  cause
       st_atime updates on the server as there are no server-side reads.  UNIX
       semantics can be obtained by disabling client-side  attribute  caching,
       but in most situations this will substantially increase server load and
       decrease performance.


BUGS
       According to POSIX.1-2008/SUSv4 Section XSI 2.9.7 ("Thread Interactions
       with Regular File Operations"):

           All of the following functions shall be atomic with respect to each
           other in the effects specified in POSIX.1-2008 when they operate on
           regular files or symbolic links: ...

       Among  the APIs subsequently listed are read() and readv(2).  And among
       the effects that should be atomic across threads  (and  processes)  are
       updates  of  the  file  offset.  However, on Linux before version 3.14,
       this was not the case:  if  two  processes  that  share  an  open  file
       description  (see  open(2))  perform a read() (or readv(2)) at the same
       time, then the I/O operations were not atomic with respect updating the
       file  offset, with the result that the reads in the two processes might
       (incorrectly) overlap in the blocks of data that they  obtained.   This
       problem was fixed in Linux 3.14.

SEE ALSO
       close(2),  fcntl(2), ioctl(2), lseek(2), open(2), pread(2), readdir(2),
       readlink(2), readv(2), select(2), write(2), fread(3)

COLOPHON
       This page is part of release 4.04 of the Linux  man-pages  project.   A
       description  of  the project, information about reporting bugs, and the
       latest    version    of    this    page,    can     be     found     at
       http://www.kernel.org/doc/man-pages/.

Linux                             2015-07-23                           READ(2)

pourtant je francise le man en post install... bon ça c'est pas trop un problème... mais on parle bien de read là ?
et help est très limité...

kiki@Sat-L500:~$ read -H
bash: read: -H : option non valable
read : utilisation : read [-ers] [-a tableau] [-d delim] [-i texte] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [nom ...]
kiki@Sat-L500:~$ read --help
bash: read: -- : option non valable
read : utilisation : read [-ers] [-a tableau] [-d delim] [-i texte] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [nom ...]
Watael a écrit :

les guillemets sont facultatifs entre double-crochets.
== est à réserver aux double-crochets.
et je n'ai pas l'impression que tu utilises de fonctionnalités avancées des double-crochets; leur emploi est alors inutile.

Donc, oui... j'ai tout repassé en simple crochet et supprimer un double == qui traînait... certainement un reste de mes cours de python lol

Par contre... tu m'intéresses... j'ai l'impression que tu as affiné ta compréhension de l'utilisation des simples et doubles crochets... sans doute depuis pas mal de temps maintenant mais ça faisait un moment que je ne t'avais pas croisé et j'ai eu l'impression lors de l'écriture de ma page sur le bash que tu étais encore un peu incertain là dessus... des nouveautés ? le man de test à évolué ?

Watael a écrit :

il faut mettre des guillemets autour de $@ pour éviter les découpages en mots et respecter le parcours des éléments d'un tableau (oui, $@ est un tableau).

Bon là c'est plus simple si c'est une règle unique et immuable !
on dit quoi alors ? $@ => "$@"... pour le parcours d'un tableau... ok ça j'avais bien pigé mais justement je jongle un peu et j'avais même pris l'habitude de ne pas les mettre...
je m'explique :
je te résume : je crée deux listes et des facons différentes de les itérer par deux avec et sans les guillemets
la première liste et les deux premiers exemples sont sans intéret...

#!/bin/bash

# ----------------------------------------------
# test bash et guillemets dans tableaux
# ----------------------------------------------

une_liste="un deux trois cat"
ligne="==========================="

echo "façon 1"
for une_ligne in $une_liste
do
    echo $une_ligne
done
echo "$ligne"

echo "façon 2"
for une_ligne in "$une_liste"
do
    echo $une_ligne
done
echo "$ligne"

jusque là facile et même sans intéret

façon 1
un
deux
trois
cat
===========================
façon 2
un deux trois cat
===========================

voilà pour l'introduction plus que basique...
mais, si je passe à la ligne, je met plusieurs mots sur une ligne, je saute même une ligne histoire de compliquer un peu le truc...

une_liste="un
deux
trois
cat le chat

et quinte"
# l'espace avant cette ligne est exprès !

echo "façon 3"
for une_ligne in $une_liste
do
    echo $une_ligne
done
echo "$ligne"

echo "façon 4"
for une_ligne in "$une_liste"
do
    echo $une_ligne
done
echo "$ligne"

là tout est dans les choux... mais c'est normal puisque je ne suis aucune règle d'écriture !

façon 3
un
deux
trois
cat
le
chat
et
quinte
===========================
façon 4
un deux trois cat le chat et quinte
===========================

jusqu'à présent j'ai écrit du code de sagouin... on est d'accord....
mais :

echo "façon 5"
IFS=$'\n'
for une_ligne in "${une_liste[@]}"
do
    echo $une_ligne
done
echo "$ligne"

echo "façon 6"
for une_ligne in ${une_liste[@]}
do
    echo $une_ligne
done
echo "$ligne"
façon 5
un deux trois cat le chat et quinte
===========================
façon 6
un
deux
trois
cat le chat
et quinte
===========================

et façon 6 en général est ce que je cherche... éclater une liste en ligne ...
Tout cela pour t'expliquer pourquoi je ne quotte plus mes variables en tableau quand je veux les itérer...
et là tu me dis : "oui mais avec $@ on met les doubles quottes... c'est ça ?"
... parce que, moi, j'avis cru comprendre le contraire...
et comme j'ai un petit pois en guise de cerveau... je retest à chaque fois... et j'en reviens toujours à cette façon d'écrire mes itérations en bash...

et quand je dis que je suis un con, ce n'est pas un euphémisme...
tu te doutes de ce que j'ai fait !!! ... et du résultat ?
parce que moi avant de faire le test, j'aurais été parfaitement incapable de dire pourquoi et comment on arrive à ce genre de sortie...
parlons en, si tu veux bien :

#!/bin/bash

# ----------------------------------------------
# test bash et guillemets dans tableaux
# ----------------------------------------------

ligne="==========================="

une_liste="un
deux
trois
cat le chat

et quinte"


fonction_de_la_mort(){
    IFS=$'\n'
    for une_ligne in "${@}"
    do
        echo $une_ligne
    done
}

fonction_de_la_muerte(){
    IFS=$'\n'
    for une_ligne in ${@}
    do
        echo $une_ligne
    done
}

echo "façon 7"
fonction_de_la_mort "$une_liste"
echo "$ligne"
echo "façon 8"
fonction_de_la_mort $une_liste
echo "$ligne"


echo "façon 9"
fonction_de_la_muerte "$une_liste"
echo "$ligne"
echo "façon 10"
fonction_de_la_muerte $une_liste
echo "$ligne"

la 7 est dans les choux et les trois autres tiennent tout juste la route...
(puisque dans aucune je ne retrouve mon fameux saut de ligne)
donc la sortie :

façon 7
un deux trois cat le chat et quinte
===========================
façon 8
un
deux
trois
cat le chat
et quinte
===========================
façon 9
un
deux
trois
cat le chat
et quinte
===========================
façon 10
un
deux
trois
cat le chat
et quinte
===========================

et bien sûr, j'ai fait sans toucher à IFS mais on passe en coupure avec les trois séparateurs : espaces / tab / saut de ligne
... si je me rappelle encore de mon mooc de bash...
... et donc, comme c'était trop capillotracté pour moi, j'avais retenue une règle : ne jamais quotter pour itérer sur les tableaux...
mais j'ai encore dû comprendre un truc de travers...

Watael a écrit :

et s'il y a des fichiers qui portent le même nom ?

Alors oui, en effet, je n'ai pas envisagé cette éventualité car, je pensais que ce genre de script est plutôt à utiliser quand on laisse s'entasser des centaines ou milliers de fichiers dans un dossier que l'on veut dispatcher vite fait avant de les traiter après coup...
... je ne sais pas si je m'explique bien...
c'est vrai qu'on est susceptible de se retrouver avec des doublons si nos dossiers sont déjà créés et qu'on ajoute après coup d'autres fichiers que l'on organise dans une seconde passe (ou x ième passe d'ailleurs)... genre utilisation du dossier magique... tu me donnes des idées là !
donc je vais ajouter une routine pour gérer les doublons éventuels... bien vu...


merci de ton assiduité et ta patience Watael  wink

Hors ligne

#6 Le 25/05/2020, à 20:34

Watael

Re : [TUTO Bash] rangement automatique fichiers par extension

ouf! tout ça, tout ça !?
smile

pour les accolades, c'est ça. Elles surchargent le code sans rien indiqué, et sont donc inutiles. Quand je vois des accolades, j'attends un Substitution de paramètres ("${var//correspondance/remplacment}", par exemple).
N'oublie pas les guillemets que toujours tu mettras autour des Développements de paramètres. TOUJOURS*; à moins de savoir pourquoi.

read -r je suis le grand coupable : je l'oublie tout le temps. c'est ma faute. je n'ai pas l'occasion d'être confronté aux problèmes que ça peut poser, alors ce n'est pas automatique. sad

il n'y a pas de man ou d'info concernant la commande interne du shell read, il faut ouvrir la page man de bash, ou taper help read pour accéder à sa description.

pour les différents tests, ça n'a pas changé; c'est probablement moi qui ait précisé ma pensée à l'usage... si j'ai seulement un clou à enfoncer, pourquoi utiliserais-je un marteau de charpentier, qui comporte un arrache-clous ?
un test simple appelle un simple test.

uneListe="un deux trois" n'est pas une liste, c'est une variable "plate", en effet, pour itérer "dessus" il faut ne pas mettre de guillemets (ça fait partie du "à moins de savoir pourquoi").
uneListe=( un deux "trois quatre" ), ça, c'est une liste, et si tu ne mets pas de guillemets, trois et quatre apparaîtront comme des éléments différents, alors qu'ils ne sont qu'un seul élément.

j'en ai oublié ?

--
* c'est valable pour les tableaux et pour $@.


Connected \o/
Welcome to sHell. · eval is evil.

Hors ligne

#7 Le 25/05/2020, à 22:26

marcus68

Re : [TUTO Bash] rangement automatique fichiers par extension

Bonjour,

La tâche initiale (classer des fichiers selon leurs extensions) peut être réalisée en genre 3 commandes, quel intérêt de faire tout ça ?

Pourquoi créer un dossier bin alors qu'un dossier est dédié à cette usage (.local/bin) et parfaitement intégré à la variable PATH ?

Pourquoi tu finis avec exit 0 ? Tu fais un mix avec un autre langage de programmation ?

Cordialement

Hors ligne

#8 Le 26/05/2020, à 01:05

MicP

Re : [TUTO Bash] rangement automatique fichiers par extension

Bonjour marcus68

marcus68 a écrit :

… Pourquoi créer un dossier bin alors qu'un dossier est dédié à cette usage (.local/bin) et parfaitement intégré à la variable PATH ? …

Ci-dessous, un extrait du fichier ~/.profile
d'un compte utilisateur non root sur debian comme sur Ubuntu :

# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/bin" ] ; then
    PATH="$HOME/bin:$PATH"
fi

Une traduction (approximative) du commentaire précédant ces quelques lignes de commande :
# définir PATH pour qu'il inclue le répertoire bin privé de l'utilisateur s'il existe

Hors ligne

#9 Le 26/05/2020, à 01:17

kholo

Re : [TUTO Bash] rangement automatique fichiers par extension

@Watael : je te le fais court : merci !!! lol

marcus68 a écrit :

Bonjour,

La tâche initiale (classer des fichiers selon leurs extensions) peut être réalisée en genre 3 commandes, quel intérêt de faire tout ça ?

Pourquoi créer un dossier bin alors qu'un dossier est dédié à cette usage (.local/bin) et parfaitement intégré à la variable PATH ?

Pourquoi tu finis avec exit 0 ? Tu fais un mix avec un autre langage de programmation ?

Cordialement

alors tout cela s'inscrit dans un ensemble de scripts que j'utilise et que je laisse utilisé à des client.e.s et à des ami.e.s...
je suis pour que le plus grand nombre aient accès à la ligne de commande et les scripts et avant eux les nautilus scripts sont une très bonne école...
mais il faut que ce soit un peu plus simple que de la ligne de commande...
donc je les relie aux nautilius scripts pour faire du clic world !
c'est un peu carrossé comme une voiture de course justement parce que j'aime bien l'idée qu'on puisse voir le moteur !

donc 3 lignes dis tu ?
avec un fichier qui associerait les extensions avec un nom pour la création d'un dossier...
elles risquent de devenir bien longues tes lignes mais je ne demande qu'à voir...
ou les jpg dans un dossier jpg et les jpeg dans un dossier jpeg... non ?
enfin, justement ce n'est pas ce que je voulais faire...

pourquoi je crée un dossier bin dans le dossier personnel ?
encore une fois, j'aime bien qu'on puisse voir le moteur...
mais la réponse se trouve par défaut dans le fichier .profile de chaque utilisateur :

# set PATH so it includes user's private bin directories
PATH="$HOME/bin:$HOME/.local/bin:$PATH"

et ce n'est pas moi mais Canonical (ou Debian... ou c'est encore plus général que ça ?!) qui l'y a mis !
On manque cruellement de normes "normalisées" en Linux... c'est à cause de la retro compatibilité je pense !
j'ai du mal à comprendre pourquoi les anciens dossiers ne disparaissent pas au profit de liens symboliques...
ça serait un signal fort... et, en plus, je croyais bien me souvenir que la création du PATH était soumise à condition...
ça doit être ailleurs...
... en cherchant pour te répondre, j'ai retrouvé ce que je m'attendais à trouver :

# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/bin" ] ; then
    PATH="$HOME/bin:$PATH"
fi

mais plus dans le mien...
... ah... et je vois le commentaire de MicP qui confirme alors même que je te répond
merci MicP wink

quant au exit 0 ?! ...
ah oui ce exit 0 est un reste de mes débuts en bash big_smile
non pas que j'ai beaucoup évolué mais ça commence à faire quelques années que je m'amuse à coder...
... c'est quand même plus évolué que du temps où je faisais du batch lol

Dernière modification par kholo (Le 26/05/2020, à 01:19)

Hors ligne

#10 Le 26/05/2020, à 07:02

marcus68

Re : [TUTO Bash] rangement automatique fichiers par extension

kholo a écrit :

donc 3 lignes dis tu ?
avec un fichier qui associerait les extensions avec un nom pour la création d'un dossier...
elles risquent de devenir bien longues tes lignes mais je ne demande qu'à voir...
ou les jpg dans un dossier jpg et les jpeg dans un dossier jpeg... non ?
enfin, justement ce n'est pas ce que je voulais faire...

non pas 3 lignes, 3 commandes. Un exemple en 4 commandes (avec le fichier extConnues.txt dans le dossier ~/.config/kholo/dorian) :

#!/bin/bash

dossier_conf="~/.config/kholo/dorian"

IFS=";"
while read extension dossier
do
	test -d "$dossier"||mkdir "$dossier"
	mv *.$extension "$dossier"
done < "$dossier_conf/extConnues.txt"

Dernière modification par marcus68 (Le 26/05/2020, à 07:04)

Hors ligne

#11 Le 26/05/2020, à 07:36

marcus68

Re : [TUTO Bash] rangement automatique fichiers par extension

bah je sais que ça fait longtemps que tu codes, mais là c'est inquiétant. smile

- Tu fais une fonction qui renvoie du texte, et les fois où elle est utilisé tu rediriges le texte vers /dev/null ?

nettoyerFichier "$file_ext_connues" >/dev/null

- Tu définies des variables nulles en début du code :

dossier_orig=""

- Tu utilises des options inutiles :

exemple ( -e sans intérêt dans a peu près tous les echo)

    echo -e "le fichier est : ${fichier_log}"

Hors ligne

#12 Le 26/05/2020, à 08:48

bruno

Re : [TUTO Bash] rangement automatique fichiers par extension

en #10
- le dossier est créé même s'il n'y a aucun fichier à déplacer ;
- le fichier est écrasé si un fichier de même nom existe déjà ;
- redéfinir globalement IFS risque de poser problème.

Hors ligne

#13 Le 26/05/2020, à 16:33

kholo

Re : [TUTO Bash] rangement automatique fichiers par extension

Bon, je prends toutes vos remarques en considération...

Pour la petite histoire :
Je rappel que mon idée n'est pas nouvelle et se basait sur un autre travail nommé dossier magique (rendons à César !) dont je parle à Watael dans ce fil et je comptais à terme améliorer et mettre au goût du jour la doc...

je vois quelques utilisations majeures à ce script :

  • le rangement automatique suite à un photorec

  • les kikoolol qui entassent les fichiers dans le dossier "téléchargement"

  • ceux qui sont aussi bordéliques que moi

  • ...

et justement, en y réfléchissant, je me suis dit que tout le monde et toutes les circonstances ne justifiaient pas les mêmes types de rangements... d'où mon idée de partir d'un fichier qui associerait extensions et noms de dossiers... association qui pourrait être choisit par la suite...
et que tous les utilisateurs n'auraient pas la connaissance pour tenir le fichier d'association (et une faute de frappe est si vite arrivée) d'où une routine qui fait les ajouts... et trie les lignes...
mais on arrive à la fin de tout cela car l'IA fera cela certainement bien mieux que n'importe quel script... et j'ai "peur" qu'on aille vers la fin des fichiers (vus par l'utilisateur final bien sûr).

Comme je vois que pas mal d'entre vous ont les capacités pourquoi ne pas repartir sur ce script et surtout qu'il fait parti de la doc, qu'il date de 2007 et était encore utilisé au moins en 2017... et comme la doc est un peu plus volatile que ce forum, je met le script tel qu'il est à ce jour avec les premières corrections pour en garder une trace :

#!/bin/bash

current_ver=1.1.1
# modifications / version 1.1
# variables en minuscules modifiées pour être facilement retrouvées
# "function" supprimé des fonctions
# accolade ouvrante des fonctions sur la même ligne que le nom de la fonction
# plus de tabulations remplacées par des espaces
# `fonction` remplacés par $(fonction)

# initialisation des options
en_terminal="est_faux"
en_aide="est_faux"
en_version="est_faux"
en_recursif="est_faux"

# Définition des fonctions du script

# Test du code retour de zenity :
testcrd(){
    if [ ${crd} = -1 ]; then
        zenity --error --title "Dossier Magique" --text "Une erreur inattendue s'est produite. Abandon."
        exit 2
    fi
    if [ ${crd} = 1 ]; then
        zenity --info --title "Dossier Magique" --text "Vous avez choisi d'annuler le script. Sortie."
        exit 1
    fi
    return 0
}

# Déplacement d'un fichier et mise à jour du fichier log :
bouge(){
    mv "${1}" "${2}"
    heure=$(date +%D-%H:%m)
    echo "[${heure}] "${1}" déplacé dans "${2}"" >> ${LOG}
    return 0
}

# Créons les répertoires s'ils n'existent pas :
createdirs(){
    mkdir -p "${fTXT}"
    mkdir -p "${fPDF}"
    mkdir -p "${fAUDIO}"
    mkdir -p "${fVIDEO}"
    mkdir -p "${fIMG}"
    mkdir -p "${fARCHIVES}"
    mkdir -p "${fDOCS}"
    mkdir -p "${fTEX}"
    mkdir -p "${fMISC}"
    mkdir -p "${fBIN}"

    return 0
}

# Trions les fichiers :
tri(){
    cd "${1}"
    # Faut-il gérer la récursivité pour les sources ?
    if [[ "${en_recursif}" = "est_vrai" && "${dir_base}" != "${1}" ]]
    then
        crd=0
        while [ ${crd} = 0 ]
        do
            ls -d */ 2> /dev/null > /tmp/tri
            crd=$?
            while read dossier
            do
                # On remonte tout le dossier d'un niveau
                mv -t "./" "${dossier}"* 2> /dev/null
                # Puis on supprime le dossier vide
                rmdir "${dossier}"
            done < /tmp/tri
        done
    fi
    ls > /tmp/tri
    while read fichier
    do
        # Cas particulier des fichiers à traiter d'après l'extension
        type="${fichier##*.}"
        case "${type}" in
            wma) bouge "${fichier}" "${fAUDIO}";;

            *)  # Utilisons si possible le type mime :
                type=$(file -bi "${fichier}")

                case "${type}" in
                    *script*) bouge "${fichier}" "${fBIN}";;
            
                    *executable*) bouge "${fichier}" "${fBIN}";;
        
                    *pdf* | *dvi* | *postscript*) bouge "${fichier}" "${fPDF}";;
            
                    *audio* | *ogg*) bouge "${fichier}" "${fAUDIO}";;
        
                    *video* | *flash*) bouge "${fichier}" "${fVIDEO}";;
    
                    *image*) bouge "${fichier}" "${fIMG}";;

                    *tar* | *rar* | *zip*) bouge "${fichier}" "${fARCHIVES}";;

                    *msword* | *excel* | *powerpoint* | *rtf* | *opendocument*) bouge "${fichier}" "${fDOCS}";;

                    *)  # Si le type mime ne suffit pas :
                        type=$(file -b "${fichier}")

                        case "${type}" in
                            *directory*) continue;;
               
                            *byte-compiled*) bouge "${fichier}" "${fBIN}";;

                            *script*) bouge "${fichier}" "${fBIN}";;
               
                            *LaTeX*) bouge "${fichier}" "${fTEX}";;
        
                            *ASF*) bouge "${fichier}" "${fVIDEO}";;

                            *text*) bouge "${fichier}" "${fTXT}";;
    
                            *)  # Le type est donc inconnu :
                                bouge "${fichier}" "${fMISC}";;
                        esac
                        ;;
                esac
                ;;
        esac
    
    done < /tmp/tri

    return 0
}


# Testons d'abord si le script est lancé en mode terminal
while getopts ":agrtv-:" OPT
do
    # gestion des options longues avec ou sans argument
    [ $OPT = "-" ] && case "${OPTARG%%=*}" in
        aide) OPT="a" ;;
        graphique) OPT="g" ;;
        recursif) OPT="r";;
        terminal) OPT="t" ;;
        version) OPT="v" ;;
        *) echo "Option inconnue" ; exit 1 ;;
    esac
    # puis gestion des options courtes
    case $OPT in
        a) en_aide="est_vrai" ;;
        g) en_terminal="est_faux" ;;
        r) en_recursif="est_vrai";;
        t) en_terminal="est_vrai" ;;
        v) en_version="est_vrai" ;;
        *) echo "Option inconnue" ; exit 1 ;;
    esac
done 

# Aide

if [ "$en_aide" = "est_vrai" ]
then
    echo "Syntaxe 1 : avec 0 ou 1 option et sans paramètre."
    echo "            $0                    Mode graphique."
    echo "            $0 -g | --graphique   Mode graphique."
    echo "            $0 -a | --aide        Affiche l'aide."
    echo "            $0 -v | --version     Affiche la version."
    echo "            $0 -r | --recursif    Gére la récursivité."
    echo "Syntaxe 2 : en mode terminal avec paramètre(s) obligatoire(s)."
    echo "            $0 -t | --terminal CIBLE [SOURCE1 ... SOURCEn]"
    echo "            où CIBLE est le dossier résultant classé"
    echo "            et SOURCE(s) le(s) dossier(s) vrac à trier."
    echo "            Si SOURCE est omis, alors CIBLE=SOURCE."
    exit 0
fi

# Version

if [ "$en_version" = "est_vrai" ]
then
    echo " "
    echo "Version $0 : $current_ver"
#    head -15 $0 | grep -v bash
    exit 0
fi

# Mémorisons le répertoire courant
old_dir_base=$(pwd)
# Initialisons le dossier racine CIBLE
dir_base="${HOME}"
# Définissons le fichier de log (aucun par défaut)
LOG="/dev/null"

# Option "terminal" pour utilisation non graphique
if [ "$en_terminal" = "est_vrai" ]
then
    # On élimine les options pour charger le(s) paramètre(s)
    while [ "${1:0:1}" = "-" ]
    do
        shift
    done
    if [ "${1}" = "" ]
    then
        echo "En mode terminal, indiquer obligatoirement le(s) paramètre(s)"
        exit 1
    fi
# Sinon, exécution en mode graphique
else
    # On affiche d'abord une fenêtre d'aide à l'utilisateur
    echo "- Vous allez tout d'abord choisir le dossier dans lequel seront créés" > /tmp/notice
    echo "  les sous-dossiers où classer les fichiers triés. C'est le dossier CIBLE." >> /tmp/notice
    echo "- Vous sélectionnerez ensuite le(s) dossier(s) ''en vrac'' dont vous" >> /tmp/notice
    echo "  voulez classer les fichiers. C'est (ce sont) le(s) dossier(s) SOURCE." >> /tmp/notice
    echo "- Note : Le dossier CIBLE peut être le même que le dossier SOURCE," >> /tmp/notice
    echo "  si les fichiers sont tous dans un même dossier. Dans ce cas, on ne" >> /tmp/notice
    echo "  peut avoir qu'un seul dossier SOURCE, qui est également la CIBLE..." >> /tmp/notice
    echo "*** Vous pouvez cliquer sur ''Annuler'' pour mettre fin au script ***" >> /tmp/notice
    zenity --text-info --title "Dossier Magique - Mode d'emploi" --height "260" --width "490" --filename "/tmp/notice"
    crd=$?; testcrd
fi

# Option "terminal" pour utilisation non graphique
if [ "$en_terminal" = "est_vrai" ]
then
    dir_base="${1}"
# Sinon, exécution en mode graphique
else
    # On sélectionne d'abord le répertoire cible
    dir_base=$(zenity --file-selection --title "Dossier Magique - Choisir répertoire CIBLE" --filename "$dir_base"/ --directory)
    crd=$?; testcrd
fi


# Option "graphique" ou par défaut pour utilisation graphique
if [ "$en_terminal" = "est_faux" ]
then
    # Protégeons le séparateur standard et initialisons-le à "|"
    OLDIFS="${IFS}"
    IFS='|'
fi
# Option "terminal" pour utilisation non graphique
if [ "$en_terminal" = "est_vrai" ]
then
    # On recherche le(s) paramètre(s) SOURCE(S) éventuel(s)
    shift
    if [ "${1}" = "" ]
    then
        # Pas de répertoire SOURCE, alors SOURCE = CIBLE
        tab_sce=("$dir_base")
    else
        # On charge le (la liste des) dossier(s) SOURCE(S)
        tab_sce=("${@}")
    fi
# Sinon, exécution en mode graphique
else
    # On peut sélectionner un ou plusieurs répertoires à trier
    # (par défaut, on trie dans le même répertoire cible=source)
    tab_sce=($(zenity --file-selection --title "Dossier Magique - Choisir répertoire(s) SOURCE" --filename "$dir_base"/ --directory --multiple))
    crd=$?; testcrd
fi

# Définition des répertoires (à adapter si besoin) :
fTXT="${dir_base}/Documents"
fPDF="${dir_base}/Documents"
fAUDIO="${dir_base}/Musique"
fVIDEO="${dir_base}/Vidéos"
fIMG="${dir_base}/Images"
fARCHIVES="${dir_base}/Archives"
fDOCS="${dir_base}/Documents"
fTEX="${dir_base}/Documents"
fMISC="${dir_base}/Divers"
fBIN="${dir_base}/Exécutables"

# Création des répertoires de tri dans le dossier cible
createdirs
for un_sce in "${tab_sce[@]}"
do
    # Option "terminal" pour utilisation non graphique
    if [ "$en_terminal" = "est_vrai" ]
    then
        tri "${un_sce}"
    else
        tri "${un_sce}" | zenity --progress --title "Dossier Magique - Transfert en cours" --auto-close --pulsate --no-cancel
    fi
done

# Restaurons le séparateur et le répertoire courant
IFS="${OLDIFS}"
cd "${old_dir_base}"

# Option "graphique" ou par défaut pour utilisation graphique
if [ "$en_terminal" = "est_faux" ]
then
    # Restaurons le séparateur standard
    IFS="${OLDIFS}"
    # Nettoyons les fichiers temporaires générés
    rm /tmp/notice /tmp/tri

    zenity --info --title "Dossier Magique" --text "Traitement terminé" --timeout "5"
fi

exit 0

Hors ligne

#14 Le 26/05/2020, à 18:18

Watael

Re : [TUTO Bash] rangement automatique fichiers par extension

vire-moi ces accolades !!! screugneugneu !!!

un nombre se teste avec une Évaluation arithmétique, ou un opérateur de comparaison arithmétique.

utiliser ls pour parcourir la liste qui en sort est une mauvaise pratique.

ce n'est pas à l'utilisateur, ou par défaut, de décider si le script s'exécute dans un terminal ou depuis une autre application graphique (typiquement le gestionnaire de fichiers).
il y a un test pour ça.

l'IFS ne se modifie pas globalement !

pourquoi est-ce qu'on a plusieurs en_terminal == vrai ?

à suivre ...


Connected \o/
Welcome to sHell. · eval is evil.

Hors ligne

#15 Le 26/05/2020, à 19:14

kholo

Re : [TUTO Bash] rangement automatique fichiers par extension

@watael
oui, j'ai pas encore regardé en profondeur ce script qui est depuis des années dans la doc !
et qui n'est pas de moi !!! lol
là j'ai juste mis un petit coup de balai histoire qu'il se lise mieux et viré les trucs dont je suis parfaitement certain et au plus rapide...
et justement je le jette un peu en pâture pour avoir l'avis des anciens autant sur le fond que la forme ; son utilité et les améliorations !
mais ok... si personne d'autre ne s'y colle je vais faire ses modifs !

Hors ligne

#16 Le 26/05/2020, à 19:30

Hizoka

Re : [TUTO Bash] rangement automatique fichiers par extension

Il aime pas les accolades Watael lol

Continue de les mettre, moi j'aime bien tongue


KDE Neon 64bits
Tous mes softs (MKVExtractorQt, HizoSelect, HizoProgress, Qtesseract, Keneric, Services menus...) sont sur github

Hors ligne

#17 Le 26/05/2020, à 20:19

Watael

Re : [TUTO Bash] rangement automatique fichiers par extension

c'est pas que j'aime pas les accolades.

Elles surchargent le code sans rien indiqué, et sont donc inutiles. Quand je vois des accolades, j'attends un Substitution de paramètres ("${var//correspondance/remplacment}", par exemple).

j'aime pas le gaspillage.
utiliser des choses en vain, c'est du gaspillage.


Connected \o/
Welcome to sHell. · eval is evil.

Hors ligne

#18 Le 26/05/2020, à 20:27

kholo

Re : [TUTO Bash] rangement automatique fichiers par extension

... en fait oui j'aime la simplicité de lecture en tant que "non" pro
mais j'ai avancé selon cette première préconisation de Watael de virer le max de guillemets accolades (en effet Watael) et voilà ce que cela donne :

#!/bin/bash

current_ver=1.1.2
# modifications / version 1.1.1
# modifs faites suite post de Watael
# https://forum.ubuntu-fr.org/viewtopic.php?pid=22291873#p22291873

# variables en minuscules modifiées pour être facilement retrouvées
# "function" supprimé des fonctions
# accolade ouvrante des fonctions sur la même ligne que le nom de la fonction
# plus de tabulations remplacées par des espaces
# `fonction` remplacés par $(fonction)

# initialisation des options
en_terminal="est_faux"
en_aide="est_faux"
en_version="est_faux"
en_recursif="est_faux"

# Définition des fonctions du script

# Test du code retour de zenity :
testcrd(){
    if [ $crd = -1 ]; then
        zenity --error --title "Dossier Magique" --text "Une erreur inattendue s'est produite. Abandon."
        exit 2
    fi
    if [ $crd = 1 ]; then
        zenity --info --title "Dossier Magique" --text "Vous avez choisi d'annuler le script. Sortie."
        exit 1
    fi
    return 0
}

# Déplacement d'un fichier et mise à jour du fichier log :
bouge(){
    mv "$1" "$2"
    heure=$(date +%D-%H:%m)
    echo "[$heure] $1 déplacé dans $2" >> $LOG
    return 0
}

# Créons les répertoires s'ils n'existent pas :
createdirs(){
    mkdir -p "$fTXT"
    mkdir -p "$fPDF"
    mkdir -p "$fAUDIO"
    mkdir -p "$fVIDEO"
    mkdir -p "$fIMG"
    mkdir -p "$fARCHIVES"
    mkdir -p "$fDOCS"
    mkdir -p "$fTEX"
    mkdir -p "$fMISC"
    mkdir -p "$fBIN"

    return 0
}

# Trions les fichiers :
tri(){
    cd "$1"
    # Faut-il gérer la récursivité pour les sources ?
    if [[ "$en_recursif" = "est_vrai" && "$dir_base" != "$1" ]]
    then
        crd=0
        while [ $crd = 0 ]
        do
            ls -d */ 2> /dev/null > /tmp/tri
            crd=$?
            while read dossier
            do
                # On remonte tout le dossier d'un niveau
                mv -t "./" "$dossier"* 2> /dev/null
                # Puis on supprime le dossier vide
                rmdir "$dossier"
            done < /tmp/tri
        done
    fi
    ls > /tmp/tri
    while read fichier
    do
        # Cas particulier des fichiers à traiter d'après l'extension
        type="${fichier##*.}"
        case "$type" in
            wma) bouge "$fichier" "$fAUDIO";;

            *)  # Utilisons si possible le type mime :
                type=$(file -bi "$fichier")

                case "$type" in
                    *script*) bouge "$fichier" "$fBIN";;
            
                    *executable*) bouge "$fichier" "$fBIN";;
        
                    *pdf* | *dvi* | *postscript*) bouge "$fichier" "$fPDF";;
            
                    *audio* | *ogg*) bouge "$fichier" "$fAUDIO";;
        
                    *video* | *flash*) bouge "$fichier" "$fVIDEO";;
    
                    *image*) bouge "$fichier" "$fIMG";;

                    *tar* | *rar* | *zip*) bouge "$fichier" "$fARCHIVES";;

                    *msword* | *excel* | *powerpoint* | *rtf* | *opendocument*) bouge "$fichier" "$fDOCS";;

                    *)  # Si le type mime ne suffit pas :
                        type=$(file -b "$fichier")

                        case "$type" in
                            *directory*) continue;;
               
                            *byte-compiled*) bouge "$fichier" "$fBIN";;

                            *script*) bouge "$fichier" "$fBIN";;
               
                            *LaTeX*) bouge "$fichier" "$fTEX";;
        
                            *ASF*) bouge "$fichier" "$fVIDEO";;

                            *text*) bouge "$fichier" "$fTXT";;
    
                            *)  # Le type est donc inconnu :
                                bouge "$fichier" "$fMISC";;
                        esac
                        ;;
                esac
                ;;
        esac
    
    done < /tmp/tri

    return 0
}


# Testons d'abord si le script est lancé en mode terminal
while getopts ":agrtv-:" OPT
do
    # gestion des options longues avec ou sans argument
    [ $OPT = "-" ] && case "${OPTARG%%=*}" in
        aide) OPT="a" ;;
        graphique) OPT="g" ;;
        recursif) OPT="r";;
        terminal) OPT="t" ;;
        version) OPT="v" ;;
        *) echo "Option inconnue" ; exit 1 ;;
    esac
    # puis gestion des options courtes
    case $OPT in
        a) en_aide="est_vrai" ;;
        g) en_terminal="est_faux" ;;
        r) en_recursif="est_vrai";;
        t) en_terminal="est_vrai" ;;
        v) en_version="est_vrai" ;;
        *) echo "Option inconnue" ; exit 1 ;;
    esac
done 

# Aide

if [ "$en_aide" = "est_vrai" ]
then
    echo "Syntaxe 1 : avec 0 ou 1 option et sans paramètre."
    echo "            $0                    Mode graphique."
    echo "            $0 -g | --graphique   Mode graphique."
    echo "            $0 -a | --aide        Affiche l'aide."
    echo "            $0 -v | --version     Affiche la version."
    echo "            $0 -r | --recursif    Gére la récursivité."
    echo "Syntaxe 2 : en mode terminal avec paramètre(s) obligatoire(s)."
    echo "            $0 -t | --terminal CIBLE [SOURCE1 ... SOURCEn]"
    echo "            où CIBLE est le dossier résultant classé"
    echo "            et SOURCE(s) le(s) dossier(s) vrac à trier."
    echo "            Si SOURCE est omis, alors CIBLE=SOURCE."
    exit 0
fi

# Version

if [ "$en_version" = "est_vrai" ]
then
    echo " "
    echo "Version $0 : $current_ver"
#    head -15 $0 | grep -v bash
    exit 0
fi

# Mémorisons le répertoire courant
old_dir_base=$(pwd)
# Initialisons le dossier racine CIBLE
dir_base="$HOME"
# Définissons le fichier de log (aucun par défaut)
LOG="/dev/null"

# Option "terminal" pour utilisation non graphique
if [ "$en_terminal" = "est_vrai" ]
then
    # On élimine les options pour charger le(s) paramètre(s)
    while [ "${1:0:1}" = "-" ]
    do
        shift
    done
    if [ "$1" = "" ]
    then
        echo "En mode terminal, indiquer obligatoirement le(s) paramètre(s)"
        exit 1
    fi
# Sinon, exécution en mode graphique
else
    # On affiche d'abord une fenêtre d'aide à l'utilisateur
    echo "- Vous allez tout d'abord choisir le dossier dans lequel seront créés" > /tmp/notice
    echo "  les sous-dossiers où classer les fichiers triés. C'est le dossier CIBLE." >> /tmp/notice
    echo "- Vous sélectionnerez ensuite le(s) dossier(s) ''en vrac'' dont vous" >> /tmp/notice
    echo "  voulez classer les fichiers. C'est (ce sont) le(s) dossier(s) SOURCE." >> /tmp/notice
    echo "- Note : Le dossier CIBLE peut être le même que le dossier SOURCE," >> /tmp/notice
    echo "  si les fichiers sont tous dans un même dossier. Dans ce cas, on ne" >> /tmp/notice
    echo "  peut avoir qu'un seul dossier SOURCE, qui est également la CIBLE..." >> /tmp/notice
    echo "*** Vous pouvez cliquer sur ''Annuler'' pour mettre fin au script ***" >> /tmp/notice
    zenity --text-info --title "Dossier Magique - Mode d'emploi" --height "260" --width "490" --filename "/tmp/notice"
    crd=$?; testcrd
fi

# Option "terminal" pour utilisation non graphique
if [ "$en_terminal" = "est_vrai" ]
then
    dir_base="$1"
# Sinon, exécution en mode graphique
else
    # On sélectionne d'abord le répertoire cible
    dir_base=$(zenity --file-selection --title "Dossier Magique - Choisir répertoire CIBLE" --filename "$dir_base"/ --directory)
    crd=$?; testcrd
fi


# Option "graphique" ou par défaut pour utilisation graphique
if [ "$en_terminal" = "est_faux" ]
then
    # Protégeons le séparateur standard et initialisons-le à "|"
    OLDIFS="${IFS}"
    IFS='|'
fi
# Option "terminal" pour utilisation non graphique
if [ "$en_terminal" = "est_vrai" ]
then
    # On recherche le(s) paramètre(s) SOURCE(S) éventuel(s)
    shift
    if [ "$1" = "" ]
    then
        # Pas de répertoire SOURCE, alors SOURCE = CIBLE
        tab_sce=("$dir_base")
    else
        # On charge le (la liste des) dossier(s) SOURCE(S)
        tab_sce=("$@")
    fi
# Sinon, exécution en mode graphique
else
    # On peut sélectionner un ou plusieurs répertoires à trier
    # (par défaut, on trie dans le même répertoire cible=source)
    tab_sce=($(zenity --file-selection --title "Dossier Magique - Choisir répertoire(s) SOURCE" --filename "$dir_base"/ --directory --multiple))
    crd=$?; testcrd
fi

# Définition des répertoires (à adapter si besoin) :
fTXT="$dir_base/Documents"
fPDF="$dir_base/Documents"
fAUDIO="$dir_base/Musique"
fVIDEO="$dir_base/Vidéos"
fIMG="$dir_base/Images"
fARCHIVES="$dir_base/Archives"
fDOCS="$dir_base/Documents"
fTEX="$dir_base/Documents"
fMISC="$dir_base/Divers"
fBIN="$dir_base/Exécutables"

# Création des répertoires de tri dans le dossier cible
createdirs
for un_sce in "${tab_sce[@]}"
do
    # Option "terminal" pour utilisation non graphique
    if [ "$en_terminal" = "est_vrai" ]
    then
        tri "$un_sce"
    else
        tri "$un_sce" | zenity --progress --title "Dossier Magique - Transfert en cours" --auto-close --pulsate --no-cancel
    fi
done

# Restaurons le séparateur et le répertoire courant
IFS="$OLDIFS"
cd "${old_dir_base}"

# Option "graphique" ou par défaut pour utilisation graphique
if [ "$en_terminal" = "est_faux" ]
then
    # Restaurons le séparateur standard
    IFS="$OLDIFS"
    # Nettoyons les fichiers temporaires générés
    rm /tmp/notice /tmp/tri

    zenity --info --title "Dossier Magique" --text "Traitement terminé" --timeout "5"
fi

exit 0

NB : encore une fois ce code n'est pas de moi alors je découvre comme vous les raisons de certains choix...
mais je trouve cela assez simple à comprendre

je vois aussi pas mal de lourdeurs que j'utilise comme le exit 0 à la fin, les accolade, ls par exemple (y en a 9 pages sur le forum ! le lien est sur la page de la doc)

Dernière modification par kholo (Le 26/05/2020, à 20:51)

Hors ligne

#19 Le 26/05/2020, à 20:43

Watael

Re : [TUTO Bash] rangement automatique fichiers par extension

virer le max de guillemets accolades.

les guillemets, au contraire, il vaut mieux en mettre en trop, que pas; comme, par exemple dans [ $OPT = "-" ]
alors qu'ils sont très facultatifs entre double-crochets, et après case.


Connected \o/
Welcome to sHell. · eval is evil.

Hors ligne

#20 Le 26/05/2020, à 21:05

marcus68

Re : [TUTO Bash] rangement automatique fichiers par extension

bruno a écrit :

en #10
- le dossier est créé même s'il n'y a aucun fichier à déplacer ;
- le fichier est écrasé si un fichier de même nom existe déjà ;
- redéfinir globalement IFS risque de poser problème.

j'avais pas saisi que tu commentait mon exemple. Je vois pas l'intérêt non plus mais on est plus à ça près.

- il suffit de rajouter un test pour que le dossier soit créé que si des fichiers existe

- mv n'ecrases pas par défaut les fichiers rajoute l'option -i à mv pour éviter ce problème

- ça tombe bien, IFS est défini exclusivement dans le script.

Mais merci wink

Dernière modification par marcus68 (Le 26/05/2020, à 23:42)

Hors ligne

#21 Le 26/05/2020, à 23:23

beuguissime

Re : [TUTO Bash] rangement automatique fichiers par extension

salut,

marcus68 a écrit :

- mv n'ecrases pas par défaut les fichiers

bah si

$ touch toto
$ touch titi
$ mv -v titi toto
renamed 'titi' -> 'toto'

Hors ligne

#22 Le 26/05/2020, à 23:41

marcus68

Re : [TUTO Bash] rangement automatique fichiers par extension

beuguissime a écrit :

salut,

marcus68 a écrit :

- mv n'ecrases pas par défaut les fichiers

bah si

$ touch toto
$ touch titi
$ mv -v titi toto
renamed 'titi' -> 'toto'

ah oui, du coup je vois pas à quoi sert l'option -f.

tu peux rajouter l'option -i alors wink

Hors ligne

#23 Le 27/05/2020, à 08:00

bruno

Re : [TUTO Bash] rangement automatique fichiers par extension

Les accolades sont déconseillées en ce moment pour conserver la distance physique.

Sinon pour marcus68, mv -i oblige à répondre à une question. S'il y a 250 fichiers dans ce cas cela va être pénible… (cf man mv pour les options) IFS pourrait très bien être utilisé plus loin dans le script, c'est pourquoi je trouve que c'est une mauvaise habitude de la modifier globalement. Il y a des alternatives, et au pire on peut la déclarer comme locale dans une fonction.

Hors ligne

#24 Le 27/05/2020, à 09:08

marcus68

Re : [TUTO Bash] rangement automatique fichiers par extension

Et donc ? C'est un exemple, on pourrait le développer, mais à quoi bon ?

Pour l'IFS il suffirait de remplacer dans le fichier de base les points virgules par des espaces, et on pourrait se passer de la variable. Et dans mon exemple cela ne gêne en rien.

Bon je suis sur que tu saisses le sujet du post [*]:mad:[/*], moi je ne veux pas développer ce script, il s'agit du script qu'à proposé kholo (voir #1).

J'ai fait l'exemple en 5 minutes pour répondre à "classer des fichiers selon leurs extensions" avec peu de commandes pour interroger la pertinence d'en faire un script de xxx lignes (voir #6). Je n'ai pas évidemment pris en compte toutes les possibilités.

Hors ligne

#25 Le 27/05/2020, à 12:57

Watael

Re : [TUTO Bash] rangement automatique fichiers par extension

Les accolades sont déconseillées en ce moment pour conserver la distance physique.

mdr !
lol


Connected \o/
Welcome to sHell. · eval is evil.

Hors ligne