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 11/08/2012, à 15:10

OL9245

[résolu] -exec basename

Bonjour,

Je ne comprend pas comment fonctionne la commande basename dans un find ... -exec.
Seule, ça fonctionne :

$ find ~/toto -maxdepth 1 -name "CRW_*.tif" -exec basename {} \;
CRW_1781.tif
CRW_1786.tif
CRW_1785.tif
CRW_1789.tif
CRW_1784.tif
CRW_1788.tif
CRW_1783.tif
CRW_1782.tif
CRW_1787.tif
CRW_1780.tif

mais impossible d'utiliser le résultat de basename pour faire quoique ce soit avec !!!
Exemple simple ci-dessous : tout est comme si basename est devenu transparent !!! il donne le nom long et non plus le nom court.

$ find ~/toto -maxdepth 1 -name "CRW_*.tif" -exec echo `basename {}` \;
/home/olivier/toto/CRW_1781.tif
/home/olivier/toto/CRW_1786.tif
/home/olivier/toto/CRW_1785.tif
/home/olivier/toto/CRW_1789.tif
/home/olivier/toto/CRW_1784.tif
/home/olivier/toto/CRW_1788.tif
/home/olivier/toto/CRW_1783.tif
/home/olivier/toto/CRW_1782.tif
/home/olivier/toto/CRW_1787.tif
/home/olivier/toto/CRW_1780.tif

Dans mon cas, j'ai besoin de créer des lien (commande ln) vers les fichiers trouvés avec find. Je sais le faire avec une instruction for do ... done mais je veux vraiment le faire avec une instruction find. Selon mes recherches, je ne suis pas le premier à avoir essayé, et dans toutes les pages que j'ai consultées, ils ont fini par prendre un workaround. Pourquoi ????

Dernière modification par OL9245 (Le 13/08/2012, à 15:05)


La farine tombée par terre ne se ramasse pas d'une seule main (proverbe burkinabé)

Hors ligne

#2 Le 11/08/2012, à 15:49

pingouinux

Re : [résolu] -exec basename

Bonjour,
Si c'est pour créer des liens, tu n'as pas besoin de la commande basename :

find ~/toto -maxdepth 1 -name "CRW_*.tif" -exec ln -s {} répertoire_où_seront_créés_les_liens \;

Si ce n'est pas ce que tu veux, précise ta demande.

Dernière modification par pingouinux (Le 11/08/2012, à 15:50)

Hors ligne

#3 Le 12/08/2012, à 11:16

OL9245

Re : [résolu] -exec basename

Merci Pingounix ! Ca résouds en grande partie mon problème courant.

Je voudrais quand même comprendre pourquoi les deux exemples que j'ai donné dans le post d'origine donnent des résultats différents. C'est bien de faire résoudre ses problèmes par les amis de la communauté. C'est encore mieux d'en profiter pour apprendre quelque chose wink


La farine tombée par terre ne se ramasse pas d'une seule main (proverbe burkinabé)

Hors ligne

#4 Le 12/08/2012, à 11:41

pingouinux

Re : [résolu] -exec basename

C'est quelque chose que j'avais déjà constaté, mais je ne sais pas pourquoi.

Hors ligne

#5 Le 12/08/2012, à 12:29

credenhill

Re : [résolu] -exec basename

hello
il exécute une fois basename {} et ensuite le exec exécute echo {}

$ set -x
$ find . -name "*.txt" -exec echo `basename {}` \;
++ basename '{}'
+ find . -name '*.txt' -exec echo '{}' ';'
./liste.txt
./ccm1/co1.txt
$ 

Hors ligne

#6 Le 12/08/2012, à 12:56

OL9245

Re : [résolu] -exec basename

Merci @ crednhill pour te pencher sur mon problème. Je retiens au passage le set -x que j'utilisais ailleurs et autrement, mais pas comme ça.

Grâce à ce truc, j'ai expérimenté ceci :

$ set -x ; 
find . -name "*.txt" -exec echo `basename /home/{}` \;
+ set -x
++ basename '/home/{}'
+ find . -name '*.txt' -exec echo '{}' ';'
./log.txt
./WarnApero.txt

On voit que :
[*]basename est exécuté avant le find
le résultat de basename /home/{} est {}
echo prend bien ce résultat comme argument, ce qui donne le nom lui-même.
[/*]

La compréhension de mon problème se dirrige donc vers une autre question : quel est l'ordre d'exécution des commandes par find, et comment le contrôler ?


La farine tombée par terre ne se ramasse pas d'une seule main (proverbe burkinabé)

Hors ligne

#7 Le 12/08/2012, à 13:04

credenhill

Re : [résolu] -exec basename

le `basename /home/{}` est exécuté par le shell et non par find -exec
on le voit bien en remplaçant basename {} par date

Dernière modification par credenhill (Le 12/08/2012, à 13:07)

Hors ligne

#8 Le 12/08/2012, à 13:26

OL9245

Re : [résolu] -exec basename

Oui, en effet. C'est ce que je voulais dire par "basename est exécuté avant le find"
Pourquoi est-ce ainsi ?
comment savoir qui va être exécuté par find et qui par le shell ?
et comment forcer une commande à être exécutée par find ?


La farine tombée par terre ne se ramasse pas d'une seule main (proverbe burkinabé)

Hors ligne

#9 Le 12/08/2012, à 13:39

pingouinux

Re : [résolu] -exec basename

@credenhill #5 : Merci pour ton explication

Il y a une façon de ruser, en utilisant un script.
Par exemple :

$ cat /tmp/mon_script
echo "$1" "$(basename "$1")"
find . -name "*.txt" -exec /tmp/mon_script {} \;

Hors ligne

#10 Le 12/08/2012, à 13:47

credenhill

Re : [résolu] -exec basename

ou comme ça

$ find . -name "*.txt" -exec bash -c 'echo $(basename {})' \;
liste.txt
co1.txt
$ 

Hors ligne

#11 Le 12/08/2012, à 14:31

pingouinux

Re : [résolu] -exec basename

@credenhill #11 :
Si les noms de fichiers contiennent des espaces, il faut modifier un peu ta commande :

find . -name "*.txt" -exec bash -c 'echo "$(basename "{}")"' \;

Hors ligne

#12 Le 12/08/2012, à 14:50

OL9245

Re : [résolu] -exec basename

credenhill a écrit :

ou comme ça

$ find . -name "*.txt" -exec bash -c 'echo $(basename {})' \;
liste.txt
co1.txt
$ 

Ah oui ! comme ça ça marche. Merci.
Sais-tu pourquoi dans la version précédente :

$ find . -name "*.txt" -exec echo `basename {}` \;

La commande basename {} est lancée par l shell avant la commande find ?
Je suppose que cela doit venir d'une règle de préprocessing de find, mais je ne trouve rien à ce sujet.


La farine tombée par terre ne se ramasse pas d'une seule main (proverbe burkinabé)

Hors ligne

#13 Le 12/08/2012, à 14:51

credenhill

Re : [résolu] -exec basename

@pingouinux : les espaces dans les noms sont interdts !!! big_smile

@OL9245: avant d'exécuter une commande le shell résoud les `` ,les $(), les ${} non protégés

Dernière modification par credenhill (Le 12/08/2012, à 14:56)

Hors ligne

#14 Le 12/08/2012, à 15:41

OL9245

Re : [résolu] -exec basename

credenhill a écrit :

@pingouinux : les espaces dans les noms sont interdts !!! big_smile

@OL9245: avant d'exécuter une commande le shell résoud les `` ,les $(), les ${} non protégés

Ah ! merci. C'est un élément de réponse.
Et comment je peux les protérer mes ``````` ?

Ceci ne marche pas :

$ find . -name "*.txt" -exec echo \`basename {}\` \;

La farine tombée par terre ne se ramasse pas d'une seule main (proverbe burkinabé)

Hors ligne

#15 Le 12/08/2012, à 15:50

credenhill

Re : [résolu] -exec basename

il y a aussi le fait que exec n'accepte qu'une commande, d'ou le bash -c plus haut

Hors ligne

#16 Le 12/08/2012, à 16:26

pingouinux

Re : [résolu] -exec basename

credenhill #15 a écrit :

@pingouinux : les espaces dans les noms sont interdts !!!

Je suis d'accord avec toi, ça devrait l'être, ainsi que tous les caractères fantaisistes. Ça éviterait bien des désagréments et des prises de tête.

Hors ligne

#17 Le 12/08/2012, à 22:36

OL9245

Re : [résolu] -exec basename

credenhill a écrit :

il y a aussi le fait que exec n'accepte qu'une commande, d'ou le bash -c plus haut

Qu'est-ce que tu entends par "qu'une commande" ?
echo , c'est "une commande".

et je reviens à ma question : comment protéger les `` pour que le shel ne les interprète pas avant find ?


La farine tombée par terre ne se ramasse pas d'une seule main (proverbe burkinabé)

Hors ligne

#18 Le 13/08/2012, à 09:46

credenhill

Re : [résolu] -exec basename

comme ça,c'est le  -exec bash qui va exécuter le echo $(basename {})'

find . -name "*.txt" -exec bash -c 'echo $(basename {})' \;

essaye ces 3 commandes pour voir les cas possibles

$ # $RANDOM est résolu pour chaque fichier
$ find . -name "*.txt" -exec bash -c 'echo $RANDOM {}' \;
$ # erreur
$ find . -name "*.txt" -exec 'echo $RANDOM {}' \;
$ # $RANDOM est résolu avant d'exécuter donc toujours le même
$ find . -name "*.txt" -exec echo $RANDOM {} \;

Hors ligne

#19 Le 13/08/2012, à 15:05

OL9245

Re : [résolu] -exec basename

Bonjour,

J'ai eu une réponse à ma question en envoyant un email à Wayne Pollock, l'auteur de http://content.hccfl.edu/pollock/unix/findcmd.htm conseillé plus baut par MicP.
Voilà ce qu'il m'a répondu :

You have it right.  The command following "-exec" is not read by
any shell by default, so shell features including command substitution
(what you tried), arithmetic substitution, comments, and so on, are not
supported.  You just get to say "-exec some_utility_name args".  So even
if you had quoted the back-quote characters, like this:

   find -name "*.txt" -exec echo \`basename\ {}\` \;  # version B, modified

it still wouldn't work.  If you want shell features, you need to
-exec the shell:

   -exec sh -c '...' \;

--------------

Sa réponse, ajoutée aux vôtres, m'a fait progresser dans ma compréhension de find. Je traduis (librement) ci-dessous
Les commandes passées par -exec ne sont pas interprétées par le shell (mais en interne par la commande find). A ce titre, la seule chose que l'on puisse y faire c'est : fais-ceci arguments. Si on a besoin du shell alors il faut demander à find d'appeler le shell en faisant -exec sh -c 'ma commande shell' \;

--------------

@credenhill : Rétrospectivement, je pense que c'est ce que tu voulais dire, par "exec n'accepte qu'une commande" mais je n'avais pas percuté.

encore merci à tous pour votre aide smile !!


La farine tombée par terre ne se ramasse pas d'une seule main (proverbe burkinabé)

Hors ligne