OVH Cloud OVH Cloud

[bash] lister/copier le contenu situé à la racine d'un dossier sans rien oublier ( comme les dot-files et les « space-files »)

38 réponses
Avatar
Francois Lafont
Bonjour à tous,

J'ai deux soucis. Dans les deux cas, je précise une fois pour toutes que
je souhaite obtenir des solutions qui gèrent correctement les noms de
fichiers avec des espaces (au début et/ou au milieu et/ou à la fin)
ainsi que les fichiers avec un nom de la forme .xxx (ie un dot-file).



1) Je souhaite lister le contenu situé à la racine d'un dossier
/dossier, c'est-à-dire tous les noms des fichiers-dossiers se trouvant à
la racine de /dossier. Alors, je pense naturellement à :

#-------------------------------------
for i in $(ls -A "/dossier"); do
echo "--$i--"
done
#-------------------------------------

Je « chope » bien les dot-files, mais ça coince avec des
fichiers-dossiers dont le nom contient des espaces. C'est un problème
simple mais pourtant je n'ai pas trouvé mieux que ça pour le résoudre :

#-------------------------------------
find "/dossier" -maxdepth 1 -mindepth 1 | while read; do
nom=$(basename "$REPLY")
echo "--$nom--"
done
#-------------------------------------

Y a-t-il plus simple que ça ? (J'espère que oui quand même).



2) Je souhaite copier tout le contenu du dossier /source vers le dossier
/cible.

« cp -r /source /cible » ne marche pas car il copie le dossier "source"
dans le dossier "cible" alors que je veux copier le contenu de "source".
« cp -r /source/* /cible » ne copie pas les dot-files. Si je fais alors
« cp -r /source/.* /cible », pour des raisons que je ne comprends pas
très bien d'ailleurs (si vous avez une explication au passage ça
m'intéresse), il y a tentative de copie de ce qui se trouve « au dessus
» de /source. Là aussi, pour un problème assez simple en somme, je n'ai
pas trouvé mieux que ça :

#-------------------------------------
find "/source" -maxdepth 1 -mindepth 1 | while read; do
cp -r "$REPLY" "/cible"
done
#-------------------------------------

Y a-t-il plus simple que ça également ?



--
François Lafont

8 réponses

1 2 3 4
Avatar
Francois Lafont
Le 01/03/2012 14:27, Luc Habert a écrit :
Francois Lafont :

Est-ce que tu as un exemple de nom qui ne marcherait pas dans ce cas là ?



Un nom de fichier avec un n dedans. Il se fera couper en deux.



Sur ma Debian Squeeze, ça n'a pas l'air de poser problème :

#--------------------------------------------
$ ls rep -l
total 0
-rw-r--r-- 1 francois francois 0 1 mars 14:19 aaaa
-rw-r--r-- 1 francois francois 0 1 mars 14:26 aaaneee

$ find rep/ -type f | while read -r; do echo "--$REPLY--"; done
--rep/aaaa--
--rep/aaaneee--
#--------------------------------------------

Ou alors je n'ai peut-être pas compris ce que tu voulais dire...

Si je comprends bien, si on veut être « béton » au niveau des noms de
fichiers, "find ... -print0 | xargs ..." est alors le seul moyen ?



En fait, il y en a un autre, à savoir

find ... -exec commande '{}' +

qui fait faire à find le boulot d'xargs. Et celui-ci est standard (la raison
qu'ils invoquent pour avoir inventer le find + plutot que de standardiser le
print0 est à se frapper la tete contre les murs). J'ai pris l'habitude
d'utiliser print0 et xargs à une époque où GNU find ne supportait pas encore
le +, et résultat, je ne pense jamais au find +.



Ok, merci pour l'info.



--
François Lafont
Avatar
Luc.Habert.00__arjf
Francois Lafont :

Sur ma Debian Squeeze, ça n'a pas l'air de poser problème :

#--------------------------------------------
$ ls rep -l
total 0
-rw-r--r-- 1 francois francois 0 1 mars 14:19 aaaa
-rw-r--r-- 1 francois francois 0 1 mars 14:26 aaaneee

$ find rep/ -type f | while read -r; do echo "--$REPLY--"; done
--rep/aaaa--
--rep/aaaneee--



Ah, j'ai compris notre incompréhension. Quand j'écris n je parle d'un
retour à la ligne, tandis que tu comprenais littérallement n, d'où ton
recours à read -r.
Avatar
Francois Lafont
Le 01/03/2012 15:03, Luc Habert a écrit :

Sur ma Debian Squeeze, ça n'a pas l'air de poser problème :

#--------------------------------------------
$ ls rep -l
total 0
-rw-r--r-- 1 francois francois 0 1 mars 14:19 aaaa
-rw-r--r-- 1 francois francois 0 1 mars 14:26 aaaneee

$ find rep/ -type f | while read -r; do echo "--$REPLY--"; done
--rep/aaaa--
--rep/aaaneee--



Ah, j'ai compris notre incompréhension. Quand j'écris n je parle d'un
retour à la ligne, tandis que tu comprenais littérallement n, d'où ton
recours à read -r.



Oui, tout à fait. Au temps pour moi. Effectivement, la commande
ci-dessus ne fonctionne pas avec un nom de fichier qui possède un retour
à la ligne.

Je pensais pas que ce n'était pas possible d'avoir un retour à la ligne
dans le nom d'un fichier. Via l'interface graphique, je n'arrive pas à
créer un tel fichier. Mais en ligne de commandes, ça passe sans problème :

#-------------------------------
$ touch 'aaa
bbb'



$ ls -l
total 0
-rw-r--r-- 1 francois francois 0 1 mars 16:41 aaa?bbb
#-------------------------------

Merci bien pour toutes ces explications. :-)
À+


--
François Lafont
Avatar
xavier
Francois Lafont wrote:

2) Je souhaite copier tout le contenu du dossier /source vers le dossier
/cible.



Pour lister, j'ai pas d'idé géniale. Pour copier, pax(1) fait très bien
l'affaire:

# mkdir newdir
# cd olddir
# pax -rwpe . ../newdir

Tout y passe : les dotfiles, les symlinks (pas sûr pour les relatifs)
etc...

--
XAv
In your pomp and all your glory you're a poorer man than me,
as you lick the boots of death born out of fear.
(Jethro Tull)
Avatar
Lucas Levrel
Le 29 février 2012, Luc Habert a écrit :

Francois Lafont :

1) Je souhaite lister le contenu situé à la racine d'un dossier
/dossier



En shell:

for f in "$dir"/* "$dir"/.[!.]* "$dir"/..?*; do
test -e "$f" || continue; # si un pattern ne matche rien, il est expansé
# en lui-même et non en rien



Pour ça on peut utiliser l'option nullglob.

# do something with $f
done



--
LL
Avatar
Francois Lafont
Je remonte ce fil pour réagir à ceci :

Le 29/02/2012 18:18, YBM a écrit :

Ce que j'en ai gardé en tête, pour des situations similaire c'est

cp -a source/. cible/ # si peu de données
(cd source ; tar cf - .) | (cd cible ; tar xf -) # si beaucoup de données

la seconde solution se trouvant terriblement performante.



Par ailleurs, y a-t-il des soucis « connus » au niveau de la commande cp
quant à des copies qui passent par le réseau ?

En effet, j'ai eu des copies ratées avec la commande cp d'un répertoire
/mnt/d qui correspond à un montage cifs vers un répertoire local /home/d.

La copie (récursive) se faisait jusqu'au bout (enfin je crois) avec
comme message à un moment :

« cp: skipping file xxx as it was replaced while being copied » .

Et le fichier en question n'était pas identique à la source ! Pourtant;
la copie portait sur une quantité de données de 500 Ko ce qui n'est pas
énorme. (Je n'arrive plus à reproduire l'erreur.)

1) Elle signifie quoi cette erreur ? Qu'au moment de la copie du
fichier, celui-ci est écrit par un autre programme ou un truc dans le
genre ?

2) Sur le Web, on trouve beaucoup de fils dans les forums où ce message
d'erreur est cité. C'est un petit bug de cp ou ou bien le montage cifs
de mon répertoire /mnt/d n'est pas correct ?



--
François Lafont
Avatar
Luc.Habert.00__arjf
Francois Lafont :

La copie (récursive) se faisait jusqu'au bout (enfin je crois) avec
comme message à un moment :

« cp: skipping file xxx as it was replaced while being copied » .



D'après le code source, ça signifie que cp a obtenu le nom du fichier, a
fait un stat dessus pour obtenir des infos dessus, l'a ouvert, a fait un
fstat sur le file descriptor obtenu, et le fstat a pondu des infos
différentes du stat précédent.

C'est normal si un autre programme (éventuellement à distance) a effacé le
fichier et mis un autre fichier sous le même nom entre l'appel à stat et
l'ouverture du fichier. Sinon, c'est un bug (coté serveur ou client).

Et le fichier en question n'était pas identique à la source !



Beuh cp a copié le fichier? Il disait qu'il le sautait.
Avatar
Francois Lafont
Je réponds un peu tardivement à ce message qui vient de tomber récemment
sur mon lecteur de news.

Le 05/03/2012 01:20, Luc Habert a écrit :

La copie (récursive) se faisait jusqu'au bout (enfin je crois) avec
comme message à un moment :

« cp: skipping file xxx as it was replaced while being copied » .



D'après le code source, ça signifie que cp a obtenu le nom du fichier, a
fait un stat dessus pour obtenir des infos dessus, l'a ouvert, a fait un
fstat sur le file descriptor obtenu, et le fstat a pondu des infos
différentes du stat précédent.



Ok, merci.

C'est normal si un autre programme (éventuellement à distance) a effacé le
fichier et mis un autre fichier sous le même nom entre l'appel à stat et
l'ouverture du fichier. Sinon, c'est un bug (coté serveur ou client).

Et le fichier en question n'était pas identique à la source !



Beuh cp a copié le fichier? Il disait qu'il le sautait.



Comme je disais, je n'ai malheureusement jamais pu reproduire l'erreur
et en fait (il était un peu tard à ce moment là) il est possible que le
message d'erreur indiqué citait un certain fichier et le fichier source
différent du fichier cible était peut-être un autre fichier, honnêtement
je ne sais plus trop.

En revanche, ce dont je suis absolument sur, c'est que j'avais une
simple commande « cp -r /mnt/d1 /home/toto/ » (avec /mnt/d1 un montage
cifs et /home/toto un répertoire « local ») et dans d1 j'avais un
fichier texte, appelons-le f, tout bête et pas bien gros (10 lignes max)
alors que sa copie /home/toto/f était foireuse. Un « cat /home/toto/f »
me retournait seulement la première ligne de f et c'est tout. Quand je
faisais « cat /home/toto/f » je voyais bien les caractères de la
première ligne s'afficher et ensuite plein de partout. J'ai eu ce
problème de copie foireuse au moins 4 ou 5 fois de suite et après je
n'ai jamais réussi à reproduire l'erreur.



--
François Lafont
1 2 3 4