#1 Le 07/07/2019, à 11: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, à 16: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, à 12: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, à 17:14)
Hors ligne
#3 Le 07/07/2019, à 14: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, à 15: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, à 15:21)
Connected \o/
Welcome to sHell. · eval is evil.
Hors ligne
#5 Le 07/07/2019, à 16:02
- nicolas84
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}"
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, à 16: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, à 17:06
- kamaris
Re : [Resolu] Variable contenant la liste des fichiers à copier pour cp
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"
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.)
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, à 17:22)
Hors ligne
#7 Le 08/07/2019, à 09: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, à 09:41)
Hors ligne
#8 Le 08/07/2019, à 12: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é.
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, à 17:08
- nicolas84
Re : [Resolu] Variable contenant la liste des fichiers à copier pour cp
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
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)
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.
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, à 17:26
- kamaris
Re : [Resolu] Variable contenant la liste des fichiers à copier pour cp
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, à 17:28)
Hors ligne