Résolu le 29-04-25 Lecture de fichier texte contenant de commande

Postez ici vos scripts Bash, Python, C++, etc...
Répondre
Joplas
Messages : 28
Enregistré le : lun. 25 nov. 2024 14:30

Lecture de fichier texte contenant de commande

Message par Joplas »

Bonjour à tous,

J'ai un souci avec un script bash me permettant de réaliser des sauvegardes/synchronisation avec rsync vers un disque dur externe.
Mon script utilise un fichier texte qui liste tous les paramètres des commandes rsync à réaliser. Cela me permet de facilement paramétrer ma sauvegarde qui comprends plusieurs rsync différents à réaliser et c'est plus claire également que de le faire dans le script où il y a d'autres choses etc.

Chaque ligne du fichier texte est un rsync à effectuer avec : la source, la destination et les options de rsync à utiliser. Ces 3 champs de données de mon fichier texte sont séparés par des tabulations. et s'il y a plusieurs options pour rsync elles sont séparées par des espaces.
Le fichier texte "list_rsync.txt" ressemble à celui ci-dessous /!\ j'ai représenté les tabulations avec le symbole "->" :

Code : Tout sélectionner

$ cat list_rsync.txt
/home/xxx/Documents/ -> /media/xxx/Documents -> --progress --delete-after
/home/xxx/Documents/fichier1.txt -> /media/xxx/Documents/fichier1_\$(date + '%Y_%m_%d').txt -> --progress
Le script bash ressemble à cela :

Code : Tout sélectionner


## lecture du fichier list_rsync.txt
nom_fic_list_sync="list_rsync.txt"
mapfile -t list_fic < "$nom_fic_list_sync" # ouverture et lecture du fichier list_rsync.txt ligne par ligne pour le mettre dans le tableau list_fic sans le caractère de fin de ligne (-t)

OIFS="$IFS" # sauvegarde ancienne valeur de IFS pour la remettre après

for i in "${!list_fic[@]}";do
	if [ ! -z "${list_fic[$i]}" -a ! "${list_fic[$i]}" = $'\n' -a ! "${list_fic[$i]:0:1}" = "#" ];then # test si ligne vide ou retour chariot ou ligne de commentaire : ne rien faire
		IFS=$'\t' # définition du délimiteur interne pour les tabulations
		read -a list_tmp_line <<< "${list_fic[$i]}" # lecture de la ligne dans un tableau avec séparateur tabluation

		source_rsync="${list_tmp_line[0]}" # source rsync
		dest_rsync="${list_tmp_line[1]}" # destination rsync
		
		eval "source_rsync=$source_rsync" # interprétation de source ?
		eval "dest_rsync=$dest_rsync" # interprétation de destination ?
		
		if [ ! -z "${list_tmp_line[2]}" ];then
			option_rsync=("--update")
		else
			IFS=$' '
			eval "option_rsync=(${list_tmp_line[$i,2]})" # options rsync
		fi
		IFS="$OIFS"
		
		rsync -avhn "${option_rsync[@]}" "$source_rsync" "$dest_rsync"
	fi
done

IFS="$OIFS" # reset variable IFS


	
	


En réalité mon script est différent car je fait des tests et je passe une options -n pour un dry mode j'ai simplifié au maximum ici en gardant la même structure.

J'en viens à mon problème : mon script qui lit le fichier "list_rsync.txt" bug lorsqu'il doit interpréter la commande "date" du nom de fichier de destination pour le rsync correspondant à la deuxième ligne du fichier.
Je suis débutant en shell... et j'ai compris qu'il fallait que j'utilise "eval" notamment pour les options de rsync. Et cela fonctionne pour les options seulement. Sinon la commande rsync considère qu'elles ne représentent qu'un seul paramètre lors de l’exécution... ce qui posait problème lorsqu'il y a deux paramètres ou plus car séparés par des espaces.
Mais concernant la date du fichier qu'il faut interpréter pour que rsync l’exécute correctement, je ne comprends pas pourquoi cela ne fonctionne pas avec les "eval" que j'ai essayé de faire en amont du rsync.
il en est de même si je mets des variables dans les noms des répertoires source ou destination par exemple : $doc qui serait définit et exporté dans mon .bashrc comme étant /home/xxx.

J'espère avoir été clair au maximum ?!

Merci de votre aide !!
Au delà du fonctionnement de ce script, je voudrais comprendre la logique de bash dans ce genre de cas sur le fonctionnement des variables et leur développement/interprétation.
Modifié en dernier par Joplas le jeu. 24 avr. 2025 11:30, modifié 3 fois.
Pc : HP Elitebook | Linux Mint 22.1 Xia | Cinnamon v: 6.4.6 | 6.8.0-49-generic x86_64 | Intel Core Ultra 5 125U | 16 GiB | Intel Meteor Lake-P
Avatar du membre
tioker
modérateur
Messages : 1144
Enregistré le : sam. 6 mai 2017 00:33
Localisation : Anjou...Feu !
Contact :

Re: Lecture de fichier texte contenant de commande

Message par tioker »

Bonsoir,

Je ne suis pas sûr d'avoir tout compris mais à priori tu mets tes commandes rsync dans un fichier txt pour qu'un script les récupère et les soumette.
J'ai [un peu] le même sujet mais beaucoup plus simple - script de mise en production de programme par copy, rsync, ftp ... dont les paramètres sont dans un fichier txt.
Donc j'ai testé et j'en suis arrivé à la conclusion suivante:
- soit la commande rsync que je mets dans une variable

Code : Tout sélectionner

cmde='rsync -rvaz /home/patrick/Documents/Programmes/Dev/DHT11/DHT11.py pi@pi4://home/pi/Documents/MeteoConcept/DHT22$(date "+%Y-%m-%d").txt'
T'as vu, j'ai mis un paramètre date ...
Si je la lance toute seule genre

Code : Tout sélectionner

$cmde
Unexpected remote arg: pi@pi4://home/pi/Documents/MeteoConcept/DHT22$(date
rsync error: syntax or usage error (code 1) at main.c(1512) [sender=3.2.7]
ça plante. Mais si je la lance avec eval, de cette manière

Code : Tout sélectionner

eval $cmde
sending incremental file list
DHT11.py

sent 595 bytes  received 35 bytes  252,00 bytes/sec
total size is 792  speedup is 1,26
ça marche.

Je ne sais pas si c'est applicable pour toi mais....

Dis nous.
ImageDistrib : Linux Mint 22.2 Desktop : X-Cinnamon
Kernel : 6.8.0-79-generic CPU : AMD Ryzen 5 5600H with Radeon Graphics RAM : 14Gi
CG : NVIDIA Corporation TU117M [GeForce GTX 1650 Mobile / Max-Q] (rev a1)
Advanced Micro Devices, Inc. [AMD/ATI] Cezanne [Radeon Vega Series / Radeon Vega Mobile Series] (rev c6)
Joplas
Messages : 28
Enregistré le : lun. 25 nov. 2024 14:30

Re: Lecture de fichier texte contenant de commande

Message par Joplas »

Bonjour à tous,

Merci de vos réponses.

J'utilise un fichier qui liste les paramètre pour rsync afin de faciliter et rendre plus clair la gestion des synchronisation. Ce fichier ne sert qu'à paramétrer rsync, le script shell execute les opérations.
De plus je réalise une redirection de sortie des rsync avec des commande | et "tee" afin d'avoir un log de ce que fait rsync paramétré pour n'avoir que ce qui m'intéresse. Donc les rsync sont en réalités un peu plus étoffés que ce que je vous ai fait voir... Donc si je mettais toutes les infos dans mon script shell, je trouve cela fastidieux de copier/coller toutes ces infos à chaque fois pour chacune de mes synchro et d'aller modifier les choses directement dans le script shell. Je préfère alors séparer les paramètres rsync que je souhaite modifier d'une synchro à l'autre dans un fichier séparé. Cela est également plus ergonomique à modifier dans le futur etc...

Je n'ajoute pas directement la date via mon script car je n'ai qu'un fichier correspondant à ce besoin parmi mes 7 synchronisation réalisées via mon fichier de liste. Donc c'est un besoin ponctuel sur un seul fichier, et je souhaite que cela soit dans mon fichier de paramétrage txt.

J'aimerais comprendre pourquoi cela ne fonctionne pas et comment le remplacement des chaînes de texte lues dans le script fonctionne.

@Tioker : En effet c'est exactement mon soucis que tu soulèves ! A ceci près que dans mon cas la variable des options de rsync est rempli par deux appelles à la fonction "read -a ..." afin de récupérer les infos du fichier texte :
  • Le 1er appelle qui utilise un séparateur tabulation pour récupérer dans un seule variable ce qui correspond aux options de sync.
  • Et le 2ème appelle qui utilise le séparateur de chaine conventionnelle IFS (espace).
  • Enfin je fait un "eval" de ce que j’obtiens.
Pc : HP Elitebook | Linux Mint 22.1 Xia | Cinnamon v: 6.4.6 | 6.8.0-49-generic x86_64 | Intel Core Ultra 5 125U | 16 GiB | Intel Meteor Lake-P
Joplas
Messages : 28
Enregistré le : lun. 25 nov. 2024 14:30

Re: Lecture de fichier texte contenant de commande

Message par Joplas »

J'ai trouvé mon problème...

Une erreur d'utilisation de la commande "date" dans mon fichier texte : j'avais un espace en trop juste après le "+" ... ! :evil:

Donc la bonne écriture est la suivante :

Code : Tout sélectionner

$(date +"%Y_%m_%d")
Le reste des "eval" fonctionne très bien en réalité !

Merci de votre aide.
Pc : HP Elitebook | Linux Mint 22.1 Xia | Cinnamon v: 6.4.6 | 6.8.0-49-generic x86_64 | Intel Core Ultra 5 125U | 16 GiB | Intel Meteor Lake-P
Répondre