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 07/07/2019, à 12:13

nicolas84

[Resolu] Variable contenant la liste des fichiers à copier pour cp

Bonjour,

J'utilise pour mes Musiques des fichiers playlist en .m3u (que je modifie à l'aide d'un script pour que tout les noms de fichiers soit en ./musique.mp3, afin que ce fichier m3u fonctionne sur tout mes appareils)
Aucun problème de ce côté là.


J'ai cherché à faire un script pour copier les fichiers contenus dans cette playlist m3u dans une clé USB ou un autre dossier par exemple.

Voici ce que j'ai fait :

#!/bin/bash

fichiers=$(sed 's/^./\"\/data\/Musiques/g; s/\x0D$//g; s/$/"/g' /data/Musiques/$1)
mkdir /tmp/test
cp ${fichiers} /tmp/test

exit 0

J'utilise sed pour remettre tout mes nom de fichier en absolu et mettre tous les noms sur une seule ligne afin de l'intégrer à la commande cd (j'ajoute aussi des "" puisque les noms ont des espaces).




La commande cp ne fonctionne pas, elle se comporte comme si il n'y avait pas les "". Elle cherche à copier chaque mot :

...
cp: cannot stat 'music': No such file or directory
cp: cannot stat '1.mp3': No such file or directory
...

Alors que j'obtiens quelques chose comme ça (en ajoutant un echo devant la commande cp) :

cp "/data/Musiques/music 1.mp3" "/data/Musiques/music 2.mp3" "/data/Musiques/music 3.mp3" /data/tmp/test

Si je copie colle le résulat de l'echo dans le terminal, cela fonctionne sans problème.




Pour le moment, je contourne comme ça :

...
echo cp ${fichiers} /data/tmp/test > /tmp/commande.sh
sudo chmod +x /tmp/commande.sh
/tmp/commande.sh

Je pourrais garder comme ça puisque cela fonctionne mais je cherche à comprendre pourquoi cela ne fonctionne pas avant.

Merci par avance

Dernière modification par nicolas84 (Le 07/07/2019, à 17:04)


SERVER : Ubuntu Server 18.04 64bit - Intel Core i3-3220 - 12GB RAM
DESKTOP : Windows 10 - Intel Core Quad Q9550 - 8GB RAM

Hors ligne

#2 Le 07/07/2019, à 13:25

kamaris

Re : [Resolu] Variable contenant la liste des fichiers à copier pour cp

Bash n'interprète pas tes guillemets, il les voit comme de simples caractères. Pour voir ce qu'il fait, tu peux faire

set -x
cp ${fichiers} /data/tmp/test

Tu vas voir qu'il te dit

+ cp '"/data/Musiques/music' '1.mp3"' '"/data/Musiques/music' '2.mp3"' '"/data/Musiques/music' '3.mp3"' /data/tmp/test

[ EDIT : non, en relisant bien ce que tu postes, ton shell semble plutôt faire un quote removal (cf. man -L en bash), mais ça ne change pas ce qui suit, ni l'utilité d'un set -x pour voir ce que fait le shell ]

Une solution qu'on ne recommande pas (eval c'est mal, ou eval is evil), c'est d'utiliser eval :

eval "cp ${fichiers} /data/tmp/test"

Mais la bonne manière de faire, c'est d'alimenter un tableau avec tes noms de fichiers :

ar=("/data/Musiques/music 1.mp3" "/data/Musiques/music 2.mp3" "/data/Musiques/music 3.mp3")
cp "${ar[@]}" /data/tmp/test

Dernière modification par kamaris (Le 07/07/2019, à 18:14)

Hors ligne

#3 Le 07/07/2019, à 15:50

nicolas84

Re : [Resolu] Variable contenant la liste des fichiers à copier pour cp

Merci pour ta réponse !

Avec eval cela ne fonctionne pas, cela me fait des retours à ligne après chaque fichier. J'ai donc des "cannot execute binary file: Exec format error" tout le long.


J'ai essayé :

ar=(${fichiers})

Cela fait la même chose qu'au départ, je suppose que je ne m'y prend pas correctement pour alimenter ce tableau


SERVER : Ubuntu Server 18.04 64bit - Intel Core i3-3220 - 12GB RAM
DESKTOP : Windows 10 - Intel Core Quad Q9550 - 8GB RAM

Hors ligne

#4 Le 07/07/2019, à 16:21

Watael

Re : [Resolu] Variable contenant la liste des fichiers à copier pour cp

il faudrait nous montrer un échantillon représentatif du fichier.m3u.

a priori :

mapfile -t ar < fichier.m3u
cp -t "$destination" "${ar[@]/#./$source}"

Dernière modification par Watael (Le 07/07/2019, à 16:21)


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

Hors ligne

#5 Le 07/07/2019, à 17:02

nicolas84

Re : [Resolu] Variable contenant la liste des fichiers à copier pour cp

Watael a écrit :

il faudrait nous montrer un échantillon représentatif du fichier.m3u.

a priori :

mapfile -t ar < fichier.m3u
cp -t "$destination" "${ar[@]/#./$source}"

Parfait, ça fonctionne !
Merci pour votre aide

Voici le script complet :

#!/bin/bash

source=/data/Musiques
file=${source}/${1}
dos2unix ${file}
fichiers=$(sed 's/^./\"\/data\/Musiques/g; s/\x0D$//g; s/$/"/g' $file)
date=`date +%y%m%d%H%M%S`
mkdir /tmp/${date}
mapfile -t ar < $file
cp -t /tmp/${date} "${ar[@]/#./$source}"

exit 0


[Edit] :
Comme je créer mes fichiers m3u sous Windows, il m'a fallu les convertir avant :

dos2unix ${file}

Même si le fichier est déjà sous un format Unix, cela ne pose pas de problèmes. Je l'ai donc ajouté au début du script

Dernière modification par nicolas84 (Le 07/07/2019, à 17:19)


SERVER : Ubuntu Server 18.04 64bit - Intel Core i3-3220 - 12GB RAM
DESKTOP : Windows 10 - Intel Core Quad Q9550 - 8GB RAM

Hors ligne

#6 Le 07/07/2019, à 18:06

kamaris

Re : [Resolu] Variable contenant la liste des fichiers à copier pour cp

nicolas84 a écrit :

Avec eval cela ne fonctionne pas, cela me fait des retours à ligne après chaque fichier.

Oui, je n'avais pas construit tout à fait la même variable que toi en local. Dans ton cas, il faudrait faire

eval "cp "${fichiers}" /data/tmp/test"
nicolas84 a écrit :

J'ai essayé :

ar=(${fichiers})

Cela fait la même chose qu'au départ, je suppose que je ne m'y prend pas correctement pour alimenter ce tableau

Oui, c'est le même problème d'interprétation des guillemets que dans « cp ${fichiers} /tmp/test » ou toute autre commande impliquant « ${fichiers} », c'est pourquoi il faut alimenter le tableau par un autre moyen (en dur en un coup comme je faisais en exemple, dans une boucle, par lecture d'un fichier comme fait par Watael, etc.)

nicolas84 a écrit :

Voici le script complet :

#!/bin/bash

source=/data/Musiques
file=${source}/${1}
dos2unix ${file}
fichiers=$(sed 's/^./\"\/data\/Musiques/g; s/\x0D$//g; s/$/"/g' $file)
date=`date +%y%m%d%H%M%S`
mkdir /tmp/${date}
mapfile -t ar < $file
cp -t /tmp/${date} "${ar[@]/#./$source}"

exit 0

Attention à mettre des guillemets autour de toute variable où pourrait figurer des espaces, pour éviter le word splitting. Ici $file si ${1} en contient, de même pour ${date} si jamais la commande date était utilisée avec un autre format plus haut.

EDIT : autre chose au passage : ta variable « fichiers » ne sert plus à rien (et donc l'invocation de sed non plus).

Dernière modification par kamaris (Le 07/07/2019, à 18:22)

Hors ligne

#7 Le 08/07/2019, à 10:40

kamaris

Re : [Resolu] Variable contenant la liste des fichiers à copier pour cp

@nicolas84 : au fait, une autre possibilité était de faire

sed 's/^./\"\/data\/Musiques/g; s/\x0D$//g; s/$/"/g' $file | xargs cp -t /tmp/${date}

@Watael : je ne comprends pas pourquoi, dans son premier message, nicolas84 obtient

...
cp: cannot stat 'music': No such file or directory
cp: cannot stat '1.mp3': No such file or directory
...

et non pas comme moi en local

...
cp: cannot stat '"/data/Musiques/music': No such file or directory
cp: cannot stat '1.mp3"': No such file or directory
...

Pourquoi nos word splitting / quote removal ne fonctionnent pas de la même manière, et qu'en est-il de ton côté ? Ma version de bash est 5.0.3(1).

Dernière modification par kamaris (Le 08/07/2019, à 10:41)

Hors ligne

#8 Le 08/07/2019, à 13:33

Watael

Re : [Resolu] Variable contenant la liste des fichiers à copier pour cp

est-ce que ça pourrait venir du fichier.m3u ? il ne nous a pas été montré. sad
je suppose que la substitution que devrait effectuer sed n'est pas réalisée.

de mon côté, sans échantillon représentatif du fichier, je ne peux rien dire de plus.


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

Hors ligne

#9 Le 08/07/2019, à 18:08

nicolas84

Re : [Resolu] Variable contenant la liste des fichiers à copier pour cp

kamaris a écrit :

Attention à mettre des guillemets autour de toute variable où pourrait figurer des espaces, pour éviter le word splitting. Ici $file si ${1} en contient, de même pour ${date} si jamais la commande date était utilisée avec un autre format plus haut.

EDIT : autre chose au passage : ta variable « fichiers » ne sert plus à rien (et donc l'invocation de sed non plus).

Merci :

#!/bin/bash

source=/data/Musiques
file=${source}/${1}
dos2unix ${file}
date=`date +%y%m%d%H%M%S`
mkdir /tmp/${date}
mapfile -t ar < ${file}
cp -t /tmp/${date} "${ar[@]/#./$source}"

exit 0
kamaris a écrit :

Pourquoi nos word splitting / quote removal ne fonctionnent pas de la même manière, et qu'en est-il de ton côté ? Ma version de bash est 5.0.3(1).

Je ne sais plus, je n'ai pas gardé de version pour revérifier ce que j'avais fait.
Ma version de bash : (Ubuntu Server 18.04)
GNU bash, version 4.4.19(1)-release (x86_64-pc-linux-gnu)


Watael a écrit :

est-ce que ça pourrait venir du fichier.m3u ? il ne nous a pas été montré. sad

Le fichier .m3u ressemble à ça :

./ARTISTE - Titre 1.mp3
./ARTISTE - Titre 2.mp3
./ARTISTE - Titre 3.mp3



En tout cas, merci encore à vous deux, le script correspond bien à mes besoins. smile


SERVER : Ubuntu Server 18.04 64bit - Intel Core i3-3220 - 12GB RAM
DESKTOP : Windows 10 - Intel Core Quad Q9550 - 8GB RAM

Hors ligne

#10 Le 08/07/2019, à 18:26

kamaris

Re : [Resolu] Variable contenant la liste des fichiers à copier pour cp

nicolas84 a écrit :

Je ne sais plus, je n'ai pas gardé de version pour revérifier ce que j'avais fait.
Ma version de bash : (Ubuntu Server 18.04)
GNU bash, version 4.4.19(1)-release (x86_64-pc-linux-gnu)

Peut-être alors ta sortie plus haut

...
cp: cannot stat 'music': No such file or directory
cp: cannot stat '1.mp3': No such file or directory
...

correspondait-elle à un cas où, pour une raison ou une autre (par exemple une commande sed un peu différente), la variable « fichiers » contenait

/data/Musiques/music 1.mp3 /data/Musiques/music 2.mp3 /data/Musiques/music 3.mp3

et non pas

"/data/Musiques/music 1.mp3" "/data/Musiques/music 2.mp3" "/data/Musiques/music 3.mp3"

Car sinon, bien que nos versions de bash soient différentes, je ne vois pas comment les guillemets auraient pu disparaitre dans le prétraitement de la commande

cp ${fichiers} /data/tmp/test

Dernière modification par kamaris (Le 08/07/2019, à 18:28)

Hors ligne