Bash: source / variable

Bonjour,

J’ai un script principal :

...
source ./script.d/variables.sh
f_test () {
find "$v_dir" -mindepth 1 -maxdepth 1 -type f  \( -iname \*.mkv -o -iname \*.mp4 \)  -exec   ./script.d/rename_file.sh {} \;
}
f_test
...

un fichier ./script.d/variables.sh pour gérer la variable array2all
et ./script.d/rename_file.sh qui commence :

...
for i in  ${array2all[@]} ;
...

quand j’exécute le script principal j’ai pas les variables.
si je source les variables depuis ./script.d/rename_file.sh ça marche.

Il me semble que sourcer dans le script principal serait mieux :confused:

J’avais testé différemment en définissant une fonction f_rename_file pour l’appeler via find mais elle n’était pas reconnu:

find "$v_dir" -mindepth 1 -maxdepth 1 -type f  \( -iname \*.mkv -o -iname \*.mp4 \)  -exec f_rename_file {} \;

Comment je peux faire pour mieux structurer ce script ?

Question complémentaire, je pensais que set -euo pipefail m’aurais mis une erreur.

Bonjour,

Tu n’as pas une erreur de chemin ou de nom du fichier, dans l’instruction source ?

Sinon utilise une structure de contrôle, comme:

[ -r ./script.d/variables.sh ] && source ./script.d/variables.sh || echo "Le fichier n'existe pas ou n'est pas accessible"

ou plus lisiblement

if [ -r ./script.d/variables.sh ] ; then
source ./script.d/variables.sh
else
echo "Le fichier n'existe pas ou n'est pas accessible"
fi

C’est un peu plus propre car ça te permet de gérer les erreurs, là j’utilise un simple echo mais on peut imaginer d’autres actions en cas d’échec à sourcer le fichier variables.sh

Et oui, -exec exécute une commande externe (depuis le répertoire dans lequel tu lances la commande find), et non une fonction interne au script dans lequel se trouve la commande find.

Ah pardon, j’étais pas super réveillé ce matin j’ai lu un peu vite !

C’est normal, la portée des variables définies par variables.sh est limitée au contexte d’exécution de variables.sh (donc à script.sh dans ton cas). Si c’est encore un autre script qui doit utiliser cette variable, il faut que ce 3e script puisse y accéder. Le plus simple est d’utiliser export, soit dans variables.sh soit dans script.sh, avec

export array2all

après avoir assigné une (ou des) valeur(s) à cette variable.

Merci

J’ai testé avec les modifs mais la variable reste vide avec export dans le script principal et aussi dans le fichier de variable.
Avant find, je peux l’afficher. Une fois dans rename_file.sh elle reste vide :confused:
Je reprendrai un peu plus tard, l’esprit aéré

J’ai trouvé quelques infos intéressantes sur le sujet pour ceux que ça intéresse.

Ah oui, il faut sourcer variables.sh dans rename_file.sh en fait. En gardant à l’esprit que la variable transformée par rename_file.sh ne sera pas connue par le script principal.

main.sh:

#!/bin/bash

[ -r ./variables.sh ] && source ./variables.sh
echo "$ma_var"
[ -r ./traitement.sh ] && bash ./traitement.sh
echo "$ma_var"

traitement.sh:

#!/bin/bash

if [ -r ./variables.sh ] ; then source ./variables.sh ; fi

ma_var="${ma_var^^}"
echo "$ma_var"

variables.sh:

#!/bin/bash

ma_var="Hello world"
$ bash main.sh 
Hello world # <= variable avant exécution de traitement.sh
HELLO WORLD # <= variable traitée par traitement.sh
Hello world # <= depuis main.sh, la variable est toujours en minuscule

Donc pas terrible. Par contre, tu peux faire autrement, en faisant en sorte d’assigner à ta variable une valeur calculée par rename_file.sh, mais au sein de script.sh, en passant ta variable en argument à l’appel de rename_file.sh:

main.sh:

#!/bin/bash

source ./variables.sh

echo "variable avant exécution de traitement.sh: $ma_var"

ma_var="$(bash traitement.sh "$ma_var")"

echo "variable après transformation par traitement.sh: $ma_var"

traitement.sh:

#!/bin/bash

var="$1"
echo "${var^^}"

variables.sh:

#!/bin/bash

export ma_var="hello world"

Ce qui donne:

$ bash main.sh 
variable avant exécution de traitement.sh: hello world
variable après transformation par traitement.sh: HELLO WORLD

Les deux commandes echo affichées sont exécutées par main.sh, on est bon.

J’ai modifié le script initial en déportant le traitement dans ./script.d/rename_file.sh parce que je n’arrive pas à gérer les noms de fichier correctement (avec des espaces et autres caractères spéciaux).

au début, ça ressemblait plutôt à ça :

filez=$(find "$v_dir" -mindepth 1 -maxdepth 1 -type f  \( -iname \*.mkv -o -iname \*.mp4 \)  -print)
for item in $filez
    do
        echo "File :  $item"
        f_rename "$item"
    done

passer la variable dans le script traitement.sh me semble pas très joli, c’est un tableau avec des regex :confused:

edit:
j’ai peut être trouvé quelque chose grâce à https://unix.stackexchange.com/a/236321
Tout dans le même fichier pour ‹ simplifier › les choses:

v_dir="$( realpath $1)"    
readarray -t filez <<<"$(find "$v_dir" -mindepth 1 -maxdepth 1 -type f  \( -iname \*.mkv -o -iname \*.mp4 \)  -print )"

    for item in  "${filez[@]}"
        do  
        ┊   echo "File :  $item"
        ┊   f_rename "$item"
        done

Je testerai quand j’aurai la machine sous les yeux mais si vous avez des remarques, ça peut toujours faire avancer la science.

Le plus compliqué à comprendre dans ton approche, c’est la démarche qui t’a rendu nécessaire l’utilisation de 3 scripts et d’arrays pour une opération de renommage de fichiers.
A tester, pour voir: 1 seul script, sans array et aucun besoin d’exportation de variables.

#!/bin/bash
v_dir="$(realpath $1)"
f_rename() { # nom de la variable: "$L"
             # commandes du script rename_file.sh
}
while read L; do echo "$L" ; f_rename
done < <(find "$v_dir" -mindepth 1 -maxdepth 1 -type f  \( -iname \*.mkv -o -iname \*.mp4 \))
exit

Pour la partie de renommage, je passe par la commande rename avec des regex.
Les règles sont stockées dans des arrays.

Je vais tester la solution proposée.

Voir encore plus simplement:

#!/bin/bash
v_dir="$(realpath $1)"
f_rename() { # nom de la variable: "$1"
             # commandes du script rename_file.sh
}
find "$v_dir" -mindepth 1 -maxdepth 1 -type f  \( -iname \*.mkv -o -iname \*.mp4 \) -print -exec f_rename {} \;
exit

Autre remarque:
Le ‹ find "$v_dir" -mindepth 1 -maxdepth 1 -type f › est un marteau-piqueur pour lister des fichiers dont le répertoire unique et les extensions sont identifiées.
Le find est inutile puisqu’il suffit de lister.

#!/bin/bash
v_dir="$(realpath $1)" && cd "$v_dir" || exit
for item in *.m{kv,p4} ; do echo "$item"
 # commandes du script rename_file.sh
done
exit

Enfin, le contenu de ‹ rename_file.sh › reste bien mystérieux avec ses arrays à regex.
Montrer quelques lignes de ce fichier permettrait peut-être de trouver d’autres optimisations avec une vision globale, et de comprendre l’intérêt ou pas de garder rename_file.sh en fichier séparé (pas démontré pour le moment).

1 J'aime