Bash: passer une liste à un script

Bonjour,

je souhaite réaliser un traitement par lots sur les noms de fichier (utiliser la commande rename en utilisant des metadonnées).

La syntaxe envisagée serait donc comme:
Renommer Truc*.jpg Truc*.JPG ./destination/

Ma question est donc comment récupérer les listes Truc*.jpg et Truc*.JPG dans un tableau du script.
Manifestement, la syntaxe suivante n’est pas la bonne:

 #!/bin/bash 
 declare -a TableauDeFichiers
 TableauDeFichiers="($1)"
   for i in "${!TableauDeFichiers[@]}"
   do      
           echo "Rang=$i - Nom=${TableauDeFichiers[$i]}"
   done

Bonjour,
D’où provient ton tableau de fichier?
d’un fichier texte? d’une liste entrée à la main? autre chose?

Ayant oublié l’existence de rename, j’utilise mv
exemple pour renomme les .JPG en .jpg
find . -maxdepth 1 -name "*JPG" |while read fich;do fich2="$(echo $fich |sed 's#JPG$#jpg#')";mv "$fich" "$fich2";done

Bonjour

Une ligne de commande bash pour renommer en jpg
tous les fichiers du répertoire courant dont le nom d’extension serait JPG

for f in *.JPG; do [ -f "$f" ] && mv "$f" "${f%.JPG}.jpg"; done

Merci à tous , mais ma question est comment charger une liste dans un script, donc dans un tableau.

En gros:
comment utiliser une liste de fichiers comme « *.jpg » dans un script

monscript.sh *.jpg

(Ensuite la fonction de renommage sera une autre question… où mv sera effectivement peut-être la solution)

Dans mon (mauvais) exemple, j’espérais charger « $1 » dans un tableau, mais « $1 » n’est qu’un seul élément.

Cette remarque me fait penser qu’il existe la variable $@, qui récupère tous les paramètres, ici tous les noms de fichier!

[EDIT]
Pb NON résolu!

La liste des fichiers obtenue par
Tableau="$@" (ou $*) ne contient qu’un seul élément qui, cette fois est bien la liste complète, mais seulement comme 1er élément du tableau:

#!/bin/bash --
# Remplir un tableau passé au script

1er essai

declare -a fichiers
for f in ${!fichiers[@]} ;
do
        echo "Rang=$f - fichier=${fichiers[$f]}"
done

# N'affiche rien

2e essai

declare -a TableauDeFichiers
TableauDeFichiers="($*)"
for i in "${!TableauDeFichiers[*]}"
do
        echo "Rang=$i - Nom=${TableauDeFichiers[$i]} "
done

# Affiche la liste dans une seule variable scalaire, avec les parenthèses et
# l'entête unique « Rang=0 »

De ces 2 exemples, les variables $* et $@ donnent le même résultat.

Il provient d’une syntaxe du shell avec jockers (truc*.jpg par exemple).

Ce n’est pas la bonne syntaxe pour parcourir les indexes d’un tableau:

for i in ${!TableauDeFichiers[*]}
do
        echo "Rang=$i - Nom=${TableauDeFichiers[$i]} "
done

Il n’y a pas de double quote dans la boucle for i in.

Mais si ton argument est « *.jpg » ca ne marchera pas. Car il faut qu’il puisse réaliser en fait ls *.jpg pour avoir une liste

Merci Zargos,
donc si je comprends bien, un script bash ne peut jamais extraire un tableau avec la syntaxe monscript *jpg ;
il est nécessaire d’écrire quelque-chose comme: monscript $(ls -1 *jpg)

Normal, c’est du shell, donc ton argument n’est pas une fonction mais juste du texte. rien d’autre. Il te faut donc interpréter ce texte.

1 J'aime

Bash possède une fonction pour créer un tableau à partir d’une entrée (comme un fichier ou la sortie d’une commande par exemple): mapfile

Si tu veux récupérer tes .jpg dans un tableau, tu peux faire quelque chose comme mapfile -t liste_jpg < <(ls -1 *.jpg)

Le -t permet de supprimer le caractère de fin de ligne de chaque élément qui sera ajouté au tableau.

1 J'aime

il me semble , après tests, que
liste_jpg=$(ls -1 *.jpg)
donne le même résultat

Cette obstination à vouloir faire un « tableau » à une seule colonne est surprenante.
Une liste de fichiers est juste une liste.

Les deux paramètres dont a besoin le script sont le répertoire de départ et celui de destination, rien de plus. Le reste relatif au tableau est de l’embrouillage inutile.

script « ren-jpg »:

#!/bin/bash
printf "Déplacement/renommage des fichiers .{jp*g,JP*G} en .jpg\n du répertoire $1 vers $2\n\n"
if [ ! -d "$2" ] ;then echo "le répertoire de destination n'existe pas"    ;exit;fi
if [ -d "$1" ] ;then cd $1 ;else echo "le répertoire initial n'existe pas" ;exit;fi

counter=0
ls *.{jp*g,JP*G} &>/dev/null && for x in *.{jp*g,JP*G} ; do
 mv "$x" "$2/${x%%.*}.jpg" && ((counter++))
done
echo "$counter fichiers traités"
exit

exemple

ren-jpg /tmp /tmp/dest2

Déplacement/renommage des fichiers .{jp*g,JP*G} en .jpg
 du répertoire /tmp vers /tmp/dest2

9 fichiers traités

Autre proposition ne nécessitant pas de saisir le nom de répertoire pour le traitement dans le répertoire courant uniquement.

#!/bin/bash
if [ "$2" ] ; then
  printf "Déplacement/renommage des fichiers .{jp*g,JP*G} en .jpg\n du répertoire $1 vers $2\n\n"
  [ -d "$1" ] && cd "$1" || R='initial'
  [ -d "$2" ] && D="$2"  || R='de destination'
  [ "$R" ] && printf "\e[35mle répertoire $R n'existe pas\n" && exit
 else
  D=$PWD
fi

counter=0
for x in $(ls |egrep -i '\.jpe?g$') ;do
 mv -n "$x" "$D/${x%%.*}.jpg" && ((counter++))
done
echo "$counter fichiers jpeg traités"
exit

Bonjour,

mon projet est de réaliser un script qui utilise les méta-données de certains fichiers pour les renommer.

Le fonction du script nécessiterait donc que j’utilise effectivement une liste passée en option, et non un répertoire (ou alors un répertoire provisoire contenant la dite liste).

Si je les comprends bien, les solutions de Verner et de Dindoun semblent me suggérer de créer d’abord un répertoire contenant seulement la sélection des fichiers à traiter.

Je vais explorer celle de Sputnik33 dés que possible: mapfile, que je ne connaissais pas et qui répeond peut-être à ma question, bien que l’exemple ne convienne pas: je souhaite passer la liste en option au script et non utiliser une liste toute faite, interne au script, comme «ls -1 *jpg.

(Par exemple, la commande rename demande en 2e argument une liste, mais elle ne permet pas d’utiliser directement une métadonnée, comme le script que j’envisage.
Peut-être faudra-t-il utiliser Perl que j’ai un peu pratiqué, mais très basiquement, il y a trop longtemps, ou Python3 que je n’ai encore jamais pratiqué. Actuellement l’engagement de l’informatique prends déja trop de place pour que j’envisage ces plaisirs de découvrir de nouveaux horizons, ou d’en redécouvrir des anciens.

merci à tous les trois.

Un problème bien posé est déjà la moitié de la solution.
Incompréhensible pour moi entre 1er et 14 ième message.
Bon courage.

@Verner
vous avez totalement raison, mais j’ai beau le savoir, ça ne suffit pas à mon savoir-faire!
C’est en lisant vos patientes réponses que j’ai pu envisager d’autres usages, mais utilisant couramment rename, j’occultai effectivement cette fonctionnalité pourtant plus évidente.
Désolé, mais ma vieille névrose est sans doute mal adaptée à ce sport cérébral pratiqué de façon trop amateur .

Encore merci

L’importance de parfaitement comprendre un problème et donc de savoir l’énoncer correctement, avant d’essayer de le résoudre, est une remarque valable pour absolument tous les domaines.
Que ce soit pour renommer ou déplacer un fichier, la commande linux ne prendra en compte que le nom réel du fichier, et non un nom approximatif extrait de quelconques « méta-données », et uniquement que pour « certains fichiers ».
Inutile d’essayer de faire un script avec ce genre d’approximations.

2 J'aime

Heureusement, j’espère effectivement avoir plus de savoir et de savoir-faire dans les domaines de la vie qui m’intéressent plus que l’informatique. Je partage vos exigences dans ces domaines où je le peux, y étant moins ignorant.

Donc en résumé, la partie renommage de fichiers jpeg à partir de meta-données dont la provenance n’est pas précisée, et exclusivement pour certains fichiers, demande une reformulation illustrée par quelques exemples pour pouvoir être testée, probablement dans un autre sujet plus clair. Impossible à deviner à partir des différentes tentatives d’explications.

Concernant le titre du sujet, et le script premier message qui laisse supposer que l’objectif est de présenter un tableau numéroté d’une liste de fichiers, la solution la plus simple est celle-ci:

$ ftest() { printf '%s\n' $@ |awk '{print NR,$0}' ;}

$ ftest fichierA.jpg fichierB.jpg fichierC.jpg
  1 fichierA.jpg
  2 fichierB.jpg
  3 fichierC.jpg

Pas sûr d’avoir vraiment compris la demande initiale, mais s’il s’agit de renommer une liste de fichiers par une liste de noms, je procède à partir d’un fichier CSV à deux colonnes :
while IFS="," read -r oldname newname ; do mv "./files/$oldname" "./files/$newname" ; done < input.csv ;
Je crée le fichier CSV avec LibreOffice, mais c’est bien sûr faisable directement dans le script, suivant l’origine des données.
En espérant n’avoir pas répondu à côté…