Google Groupes n'accepte plus les nouveaux posts ni abonnements Usenet. Les contenus de l'historique resteront visibles.

[bash] bonne façon de faire une boucle sur un ensemble de fichiers contenu dans un dossier

10 vues
Accéder directement au premier message non lu

Francois Lafont

non lue,
22 mai 2011, 12:27:5622/05/2011
à
Bonjour à tous,

Assez régulièrement, je suis amené à me faire des petits scripts bash
qui font une boucle sur une liste de fichiers contenus dans un dossier
(et dans ses sous-dossiers etc). La liste de fichiers, qui peut être
assez grande, est obtenue à l'aide de la commande find. Le but est de
faire un même petit traitement sur chacun des fichiers de cette liste
via une boucle (le traitement importe peu ici, ça peut être un
"renommage", un grep etc). La structure de mes petits scripts
ressemblent à ça du coup (c'est un exemple) :

#-------------------------------------
for fichier in $(find /le/dossier/ -type f -iname '*.tex')
do
echo Traitement de $fichier
# etc.
done
#-------------------------------------

Est-ce la bonne façon de procéder ? J'ai des doutes :


1) En effet, finalement le script revient à ça :

#-------------------------------------
for fichier in /le/dossier/f1.tex /le/dossier/f2.tex /le/dossier/f3.tex
do
echo Traitement de $fichier
# etc.
done
#-------------------------------------

Du coup, si la liste est très grande, ça me semble un peu maladroit
comme script et peut-être pas très performant. (Aucune certitude bien
sûr, c'est juste une intuition.)

2) Une autre chose qui me fait penser que ce n'est peut-être pas la
bonne façon de procéder, c'est le problème avec les noms de fichiers qui
contiennent un espace. Si find détecte un fichier qui s'appelle par
exemple "/le/dossier/sous dossier/toto.tex" alors, durant la boucle,
$fichier sera égal à la chaîne "/le/dossier/sous" puis à
"dossier/toto.tex" mais jamais à "/le/dossier/sous dossier/toto.tex".

Bref, quelle est la bonne façon de faire ce genre de boucle ?
Merci d'avance pour votre aide.


--
François Lafont

Doug713705

non lue,
22 mai 2011, 12:34:4922/05/2011
à
Le 22-05-2011, Francois Lafont nous expliquait dans
fr.comp.os.linux.configuration :

> Bonjour à tous,

Bonjour,

> #-------------------------------------
> for fichier in $(find /le/dossier/ -type f -iname '*.tex')
> do
> echo Traitement de $fichier
> # etc.
> done
> #-------------------------------------
>
> Est-ce la bonne façon de procéder ? J'ai des doutes :

Je ne suis pas spécialiste mais je pense que tu peux jetter un oeil à
l'option -exec de find.

D'autres options de manipulation de fichier existent également
(-delete par ex).

man find
--
Doug - Linux user #307925 - Slackware64 roulaize ;-)
http://www.dougwise.org
http://usenet-fr.dougwise.org
http://news.dougwise.org

Aéris

non lue,
22 mai 2011, 12:35:0722/05/2011
à
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Le 22/05/2011 18:27, Francois Lafont a écrit :
> for fichier in $(find /le/dossier/ -type f -iname '*.tex')
> do
> echo Traitement de $fichier
> # etc.
> done

find /le/dossier/ -type f -iname '*.tex' | while read FILE; do
echo "${FILE}"
done

- --
Aeris
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJN2Ts0AAoJEK8zQvxDY4P938sIAMCNjiya/RT0hJHza5O8r0aN
K3X1iutv+bCYQVm06DeU9toIhIxAh72OAQIxzzmFPycNVC+bUe3QMsCltClcRkhj
PnnswG9m1TfB6AYyUfMt3KkEspzHeDnC6OvYNGRegWe1uO30mePApI9+R7tpYpmz
3u7hIOi51CqmTve8P7xuh67SQYKqwPKkXWYOGscLI7kpaWY5720O4LVH90uCsR3x
7usbUA+C+vENxWTMz1NNmp67MwZoUSWXloYBDAABkJ6QPs38KUoj63KvCym0eRBM
NWE8UeBIQy/GpaGPmlVwhpOdWyc2wwpfCd1UkqOb5LEf67bjJLBmgQmZbk3dqxM=
=w5K9
-----END PGP SIGNATURE-----

Francois Lafont

non lue,
22 mai 2011, 12:43:1122/05/2011
à
Le 22/05/2011 18:34, Doug713705 a écrit :

> Je ne suis pas spécialiste mais je pense que tu peux jetter un oeil à
> l'option -exec de find.

Oui, je connais l'option -exec mais le souci c'est que même si le
traitement sur chaque fichier est assez basique en général, il m'est
souvent difficile de le faire tenir sur une seule ligne. Du coup,
j'avais pensé à faire un truc dans ce genre :

function f(){
echo Traitement de $1
# etc.
}

find /le/dossier/ -type f -exec f {} \;

Mais dans l'option -exec, la fonction f semble totalement inconnue et le
code ne fonctionne pas.


--
François Lafont

Francois Lafont

non lue,
22 mai 2011, 12:55:0922/05/2011
à
Le 22/05/2011 18:35, Aéris a écrit :

> find /le/dossier/ -type f -iname '*.tex' | while read FILE; do
> echo "${FILE}"
> done

Merci bien Aéris, ça m'a l'air parfait. J'aimerais simplement comprendre
la différence entre ${FILE} et $FILE, je ne vois pas trop.


--
François Lafont

Le message a été supprimé

Nicolas George

non lue,
22 mai 2011, 13:07:2322/05/2011
à
Francois Lafont , dans le message
<4dd9395e$0$18114$426a...@news.free.fr>, a écrit :

> Assez régulièrement, je suis amené à me faire des petits scripts bash
> qui font une boucle sur une liste de fichiers contenus dans un dossier
> (et dans ses sous-dossiers etc). La liste de fichiers, qui peut être
> assez grande, est obtenue à l'aide de la commande find.

Jette bash en faveur de zsh :

setopt extendedglob
for f in **/*.(#i)tex; {
... frobincate $f
}

Aéris

non lue,
22 mai 2011, 13:10:0322/05/2011
à
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Le 22/05/2011 18:55, Francois Lafont a écrit :
> Merci bien Aéris, ça m'a l'air parfait. J'aimerais simplement comprendre
> la différence entre ${FILE} et $FILE, je ne vois pas trop.

Y'en a pas vraiment.
{} te permet juste de faire des trucs plus complexes, du style
BIDULE=truc
echo "${BIDULE}muche"
Sans les accolades, ça serait impossible.

Et j'ai pris l'habitude de les mettre partout du coup =)

- --
Aeris
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJN2UNiAAoJEK8zQvxDY4P9fhoH/ihb0ZWiFqb+8nUtVP67T+l5
Ph9eMCQ9UhqxApvQuVnuKoWWzdBH/QA/C962MRCTvsic4PCyzy5Hz3OxggYED+VG
K3LskAvdM6CR5kz79dkQMxEpGqkhJrLwUgViUcRvrlsGiVzqMtfKqKlfD36Ip34h
aeY2w00gM9HO7rEvyX1feL3W/5vR8Fe4+AF3KzQ41PgX/Lay4THhwYAbsiAHwHFh
XhTjskjhhJFdJa8JxK5+oCg7nw836pXfjqJrT8FqKTKTr9BonKEY4vyKFA/sB0nL
vwandErpWH55Ycnp78uXD/mPJS6BM5rnUtDIRzktAs50JQmMNzoLF9fUb7NnO0o=
=zLmP
-----END PGP SIGNATURE-----

Nicolas George

non lue,
22 mai 2011, 13:29:5922/05/2011
à
Xavier, dans le message <1k1onot.3j3u907xvcw0N%xav...@groumpf.org>, a
écrit :
> Faut exporter la fonction, et lancer un shell dans exec :
>
> export func
> find /dossier-type f -exec sh -c 'func $1' _ {} \;

N'importe quoi.

Nicolas George

non lue,
22 mai 2011, 13:30:3022/05/2011
à
Aéris , dans le message <4dd9436b$0$13039$426a...@news.free.fr>, a
écrit :

> BIDULE=truc
> echo "${BIDULE}muche"
> Sans les accolades, ça serait impossible.

echo "$BIDULE""muche"

Francois Lafont

non lue,
22 mai 2011, 13:33:0122/05/2011
à
Le 22/05/2011 19:07, Xavier a écrit :

>> find /le/dossier/ -type f -exec f {} \;
>>
>> Mais dans l'option -exec, la fonction f semble totalement inconnue et le
>> code ne fonctionne pas.
>

> Faut exporter la fonction, et lancer un shell dans exec :

Ok, mais j'imagine pour le coup que les performances s'en trouvent
amoindries.

> export func
> find /dossier-type f -exec sh -c 'func $1' _ {} \;

Je crois qu'Aéris a parfaitement résolu mon problème, ceci étant, par
curiosité, j'ai essayé de faire fonctionner cette idée et je n'y suis
pas arrivé. J'ai fait ça :

function f(){
echo Traitement de $1
}

export f
find /le/dossier -type f -exec sh -c 'f $1' _ {} \;

Je ne comprends pas trop le «-c 'f $1'» et le underscore qui vient juste
après. J'ai bien tenté un "man sh", mais je tombe sur la page du shell
dash ?

Nicolas George a écrit :

> Jette bash en faveur de zsh :
>
> setopt extendedglob
> for f in **/*.(#i)tex; {
> ... frobincate $f
> }

Ah, j'ai peur de ne pas avoir le temps. Mais peut-être un jour... Ce
n'est pas la première qu'on me parle en bien de zsh.


Aéris a écrit :

> Y'en a pas vraiment.
> {} te permet juste de faire des trucs plus complexes, du style

> BIDULE=truc
> echo "${BIDULE}muche"
> Sans les accolades, ça serait impossible.
>

> Et j'ai pris l'habitude de les mettre partout du coup =)

Ok, je vois. Perso, j'utilise les doubles quote :

BIDULE=truc
echo "$BIDULE"muche

En tout cas, merci bien Aéris pour ta solution.


--
François Lafont

Le message a été supprimé

Aéris

non lue,
22 mai 2011, 14:00:0122/05/2011
à
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Le 22/05/2011 19:30, Nicolas George a écrit :
> echo "$BIDULE""muche"

Oui mais des fois tu ne pourras pas t'en sortir avec des quotes.

Sans parler des
BIDULE=foo:bar
echo ${BIDULE%:*}
ou encore
unset NOT_EXISTING
echo ${NOT_EXISTING:-defaultValue}

- --
Aeris
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJN2U8cAAoJEK8zQvxDY4P9hLsIAJYXMa1ZvHw5ttk23a1rwTmy
2uewngQzUa6OYpoOU8zUuwQ/vI7GWAfgBRwFUjsNySQNW5R67BvlLBQcbtJF809s
xXTMW9iguw4ov6ZTtanOMOe95jgAip0+2OrC5xQtWxngXphVUBBiC8YH0wLZpzb2
1p0mYXOjlvObyT7njZxN9jeDR07FAX8Jwpnz0L931cnx4g0t5q4MVwASmS+j6uI/
SrmeMruWjZKdZmPiSekfilINsRCRhUaItWqxquETc5111JUmhtd/3ScqY3ifOQ3i
APNrKiT8IskF4Nz88C/w9eskTX1r6qaAgZUqCOzimTkwjpOHw9fcOJWrbW8m/xg=
=SqVi
-----END PGP SIGNATURE-----

Nicolas George

non lue,
22 mai 2011, 14:00:3922/05/2011
à
Xavier, dans le message <1k1ops0.wg09de1p7sta8N%xav...@groumpf.org>, a
écrit :
> Je n'ai jamais trouvé d'autre moyen pour faire exécuter une fonction du
> script en cours par find -exec

On ne peut pas, point. Et exporter n'a aucun sens pour une fonction, ça n'a
de sens que pour une variable.

Francois Lafont

non lue,
22 mai 2011, 14:32:2722/05/2011
à
Le 22/05/2011 20:00, Nicolas George a écrit :

>> Je n'ai jamais trouvé d'autre moyen pour faire exécuter une fonction du
>> script en cours par find -exec
>
> On ne peut pas, point.

Personnellement, je n'ai pas réussi à faire fonctionner l'exemple de
Xavier. Si vous avez un mini exemple complet qui marche... Mais bon,
c'est juste par curiosité.


--
François Lafont

Nicolas George

non lue,
22 mai 2011, 14:54:5522/05/2011
à
Francois Lafont , dans le message
<4dd9568c$0$20808$426a...@news.free.fr>, a écrit :
> Personnellement, je n'ai pas réussi à faire fonctionner l'exemple de
> Xavier.

C'est normal.

> Si vous avez un mini exemple complet qui marche...

Il n'y en a pas, sa solution juste ne marche pas.

Le message a été supprimé

Nicolas George

non lue,
22 mai 2011, 17:07:5422/05/2011
à
Xavier, dans le message <1k1ov9c.10i21tu17wx174N%xav...@groumpf.org>, a
écrit :
> Testé et validé. Bon, sur MacOSX, sh est un hardlink de bash, mais je ne
> crois pas que cela change grand chose...

Si, ça change tout.

Et accessoirement, ça pue le trou de sécurité à dix kilomètres.

Floris Dubreuil

non lue,
22 mai 2011, 23:02:5922/05/2011
à
Le 22/05/2011 18:27, Francois Lafont a écrit :
> Bonjour à tous,

>
> Bref, quelle est la bonne façon de faire ce genre de boucle ?

Ben, j'ai comme un doute en voyant toutes les réponses avant moi mais, à
tout hasard, xargs ça sent le paté ?

Cdlt,

--
Floris Dubreuil

Sergio

non lue,
23 mai 2011, 01:49:2123/05/2011
à
Le 22/05/2011 22:04, Xavier a écrit :

> -----------
> #!/bin/sh
>
> myls () {
> F="$1"
> echo "$F"
> }
>
> export -f myls
>
> find /usr/bin -type f -exec sh -c 'myls $1' _ {} \;
> ----------


>
> Testé et validé. Bon, sur MacOSX, sh est un hardlink de bash, mais je ne

> crois pas que cela change grand chose... A part ça, c'est du code de
> test, évidemment.

Pour avoir vaguement manipulé, il me semble que le "find" de Mac OS/X est un peu réduit par rapport au find de Linux, non ?

--
Serge http://leserged.online.fr/
Mon blog: http://cahierdesergio.free.fr/
Soutenez le libre: http://www.framasoft.org

Le message a été supprimé

Aéris

non lue,
23 mai 2011, 14:08:2223/05/2011
à
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Le 23/05/2011 05:02, Floris Dubreuil a écrit :
> Ben, j'ai comme un doute en voyant toutes les réponses avant moi mais, à
> tout hasard, xargs ça sent le paté ?

Avec des espaces dans le nom de fichier, oui?

- --
Aeris
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJN2qKWAAoJEK8zQvxDY4P96pgH/01TPvoeaAbCeuTPj4t+pZZn
61/HCkrJILJAA5kufjI/JdgqQ2XLPH0ITY3H2nzrfvnuYHjre68Nk8aK8xhwWbmN
vBaDXW3ONsh7hRQtbTTH2OpO1Vtn45ekSKJvZFy6k3bKKLigtGw+kRXbiFrP8Pe4
xDkhMjbGr/y65IsJT4uwA/omHwTPSWWcIYbYtPhieyCscr2TPt3w7A+oUgZUV0Yp
63SbDqa5g+Evl9ybL3H5TD77bHYKnCJDR/67l0kSZ4aW6HPkLV89JgQw7HNZkWvz
BE5GbzlvfGtGhpjZ2xyeGLkK/7ruTZdzVHep3nUmsi/+RGsvEEFJ72cHofcnIbI=
=MG1d
-----END PGP SIGNATURE-----

Floris Dubreuil

non lue,
23 mai 2011, 14:40:2623/05/2011
à
Le 23/05/2011 20:08, Aéris a écrit :
>> xargs ça sent le paté ?
>
> Avec des espaces dans le nom de fichier, oui?

On doit pas aller chez le même charcutier...

# find -name "*.tex" | xargs -d "\n" du

0 ./un dossier avec des espaces/titi.tex
0 ./deux dossiers avec des espaces/toto.tex


# find -name "*.tex" -print0 | xargs -0 du

0 ./un dossier avec des espaces/titi.tex
0 ./deux dossiers avec des espaces/toto.tex


=> Le second exemple a l'avantage de fonctionner avec tous les
caractères ésotériques que peuvent contenir les noms de fichiers, y
compris les sauts de ligne.

=> Voir
http://linuxfr.org/forums/g%C3%A9n%C3%A9ralcherche-logiciel/posts/caract%C3%A8re-sp%C3%A9ciaux-avec-xargs

Exemple avec les fichiers, eux aussi, avec des noms ayant des espaces:

# find -name "*.tex" -print0 | xargs -0 du
0 ./un dossier avec des espaces/un fichier avec des espaces.tex
0 ./deux dossiers avec des espaces/deux fichiers avec des espaces.tex

Cétipabo ?

Cordialement,

--
Floris Dubreuil


Benoit Izac

non lue,
23 mai 2011, 15:03:3523/05/2011
à
Bonjour,

le 23/05/2011 à 20:40, Floris Dubreuil a écrit dans le message
<4ddaaa1c$0$4774$426a...@news.free.fr> :

> # find -name "*.tex" -print0 | xargs -0 du
> 0 ./un dossier avec des espaces/un fichier avec des espaces.tex
> 0 ./deux dossiers avec des espaces/deux fichiers avec des espaces.tex
>
> Cétipabo ?

Ça ne répond pas à la question initiale où il était question de lancer
plusieurs commandes sur le fichier. Pas besoin de xargs pour faire juste
un « du » :

find -name "*.tex" -exec du {} + (qui à l'avantage d'être portable)

--
Benoit Izac

Floris Dubreuil

non lue,
23 mai 2011, 17:19:0423/05/2011
à
Le 23/05/2011 21:03, Benoit Izac a écrit :
> Bonjour,

> Ça ne répond pas à la question initiale où il était question de lancer
> plusieurs commandes sur le fichier. Pas besoin de xargs pour faire juste
> un « du » :

Je ne répondais plus à l'auteur, mais à Aéris, lui démontrant qu'il est
possible d'utiliser xargs avec des espaces.

J'ai utilisé "du" pour suivre l'exemple donné sur linuxfr.org

> find -name "*.tex" -exec du {} + (qui à l'avantage d'être portable)

Pas spécialement, le package find n'est pas le même partout et certains
systèmes n'ont pas le "full option".

J'ai déjà eu des soucis de compatibilité dans les commandes exotiques
avec "find -exec", jamais avec xargs.

A l'usage, find -exec est plus rapide.

Cdlt,

--
Floris Dubreuil

Francois Lafont

non lue,
23 mai 2011, 18:21:1023/05/2011
à
Re, :-)

Bon vraiment mon problème est résolu, et ce depuis quasiment le début du
fil. Bref, je suis satisfait à 100%. Là, je vais juste finasser un peu.
Je viens de m'apercevoir qu'en fait avec la construction de la boucle
via la commande read (solution d'Aéris), les noms qui commençaient et/ou
se terminaient par des espaces étaient tronqués ("stripés"). Par exemple
(avec bash), ce code :

#----------------------------
echo $' aaa \n bbb ' | while read fichier
do
echo debut---$fichier---fin
done
#----------------------------

me donne en sortie :

debut---aaa---fin
debut---bbb---fin

Je comprends bien pourquoi (je pense), mais y a-t-il moyen de faire en
sorte d'avoir en sortie ceci ?

debut--- aaa ---fin
debut--- bbb ---fin

Bon, j'avais prévenu que j'allais finasser car il faut vraiment être
tordu pour avoir des noms de fichiers qui commencent et/ou se finissent
par des espaces. Mais sur ma Debian Squeeze, ça semble parfaitement
autorisé (par exemple touch " fichier " passe sans problème).


--
François Lafont

Aéris

non lue,
23 mai 2011, 20:13:4823/05/2011
à
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Le 24/05/2011 00:21, Francois Lafont a écrit :
> echo $' aaa \n bbb ' | while read fichier
> do
> echo debut---$fichier---fin
> done

echo ' aaa \n bbb ' | while IFS=$'\n' read fichier
do
echo debut---${fichier}---fin
done

- --
Aeris
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJN2vg8AAoJEK8zQvxDY4P92tQH/jOGpg/naAXSCzEfOAr+oSwN
/TwMAGBllp/+/zTxKlYbv7dZp9Cay1Uq2PVIY/cInBd92B3uGUVwuY7nNJrz3Jyr
3VAKVMhS78hgpT55reLdmo11T725znOyJf/Qs0JWuewSYMdR4ROD50XSWvnrvvD6
/cZ34/GPpe+Bjv/WBjYZk/Bu79NQOiCVngDnRchVlcT8ZdJquUoN9F+NKxrBh3Sp
GR88S+akdlgA/qGoFkxz6/f0MgTkcYo41egcHEwQW8BfpOJetOkoUA8QpwiQswBx
kJGxfKRCSIls2h9acwJIE/1WsHgFrE4y+FzLS7Moj1jUxy/uEU4qbrVpzdaSiko=
=nbno
-----END PGP SIGNATURE-----

Francois Lafont

non lue,
24 mai 2011, 12:22:5324/05/2011
à
Le 24/05/2011 02:13, Aéris a écrit :

> echo ' aaa \n bbb ' | while IFS=$'\n' read fichier
> do
> echo debut---${fichier}---fin
> done

Merci bien Aéris pour cette proposition. En fait, je pense que tu as
oublié de mettre un $ après la commande echo. Mais ceci est anecdotique.
Du coup, j'ai testé ce code :

#---------------------------------------------
echo $' aaa \n bbb ' | while IFS=$'\n' read fichier


do
echo debut---${fichier}---fin
done

#---------------------------------------------

Et j'ai en sortie ceci :

debut--- aaa ---fin
debut--- bbb ---fin

ce qui ne correspond pas exactement au résultat souhaité. En fait, je ne
comprends pas pourquoi on obtient ce résultat et pourquoi on n'obtient
pas ça ?

debut--- aaa ---fin
debut--- bbb ---fin

Pire : je ne comprends même pas pourquoi le code fonctionne car je
pensais qu'il y manquait un « && » entre « IFS=$'\n' » et « read
fichier ». Du coup, j'ai testé ce code :

#---------------------------------------------
echo $' aaa \n bbb ' | while IFS=$'\n' && read fichier


do
echo debut---${fichier}---fin
done

#---------------------------------------------

Et lui me donne bien comme résultat :

debut--- aaa ---fin
debut--- bbb ---fin

Du coup, il y a vraiment des choses qui m'échappent. Si vous avez des
explications, je suis preneur.

De plus, savez comment on peut faire pour connaître le contenu de IFS
exactement. Si je fais un echo "$IFS" > out.txt, je pense pouvoir
deviner comme contenu « ESPACE, TAB puis \n ». Mais y a-t-il un moyen de
voir son contenu de manière plus lisible ?


--
François Lafont

Benoit Izac

non lue,
24 mai 2011, 12:22:3724/05/2011
à
Bonjour,

le 23/05/2011 à 23:19, Floris Dubreuil a écrit dans le message
<4ddacf4a$0$7168$426a...@news.free.fr> :

>> find -name "*.tex" -exec du {} + (qui à l'avantage d'être portable)
>
> Pas spécialement, le package find n'est pas le même partout et
> certains systèmes n'ont pas le "full option".

Quand je dis portable, il faut comprendre POSIX. L'option « -0 » de
find ou xargs n'est pas défini dans SUSv3 :
<http://pubs.opengroup.org/onlinepubs/009695399/utilities/find.html>
<http://pubs.opengroup.org/onlinepubs/009695399/utilities/xargs.html>

--
Benoit Izac

Aéris

non lue,
24 mai 2011, 14:13:5524/05/2011
à
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Le 24/05/2011 18:22, Francois Lafont a écrit :
> Merci bien Aéris pour cette proposition. En fait, je pense que tu as
> oublié de mettre un $ après la commande echo. Mais ceci est anecdotique.
> Du coup, j'ai testé ce code :

Effectivement, mais sous zsf il n'y en a pas besoin =)

>
> #---------------------------------------------
> echo $' aaa \n bbb ' | while IFS=$'\n' read fichier
> do
> echo debut---${fichier}---fin
> done
> #---------------------------------------------
>
> Et j'ai en sortie ceci :
>
> debut--- aaa ---fin
> debut--- bbb ---fin


Je n'ai pas du tout ça:

~$ echo $' aaa \n bbb ' | while IFS=$'\n' read fichier; do echo
"debut---${fichier}---fin"; done


debut--- aaa ---fin
debut--- bbb ---fin


> Pire : je ne comprends même pas pourquoi le code fonctionne car je
> pensais qu'il y manquait un « && » entre « IFS=$'\n' » et « read
> fichier ». Du coup, j'ai testé ce code :
>
> #---------------------------------------------
> echo $' aaa \n bbb ' | while IFS=$'\n' && read fichier
> do
> echo debut---${fichier}---fin
> done
> #---------------------------------------------

Ceci est faux.
« IFS=$'\n' » n'est pas une commande mais la définition d'une variable
d'environnement inline.
Mais le résultat est correct quand même car la définition d'une variable
n'échoue jamais (code de retour > 0) et donc « && » sera toujours évalué.

On peut généraliser cela très facilement :
— Changement de langue à la volée
~$ man toto
Aucune entrée de manuel pour toto
~$ LANG=C man toto
No manual entry for toto
— Changement du path temporaire:
~$ /usr/bin/which man
/usr/bin/man
~$ PATH= /usr/bin/which man
~$
etc

> De plus, savez comment on peut faire pour connaître le contenu de IFS
> exactement. Si je fais un echo "$IFS" > out.txt, je pense pouvoir
> deviner comme contenu « ESPACE, TAB puis \n ». Mais y a-t-il un moyen de
> voir son contenu de manière plus lisible ?

echo $IFS | hexdump -C
00000000 20 09 0a 00 0a | ....|
00000005

0x20 = espace
0x09 = tabulation
0x0a = saut de ligne
0x00 = null

- --
Aeris
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJN2/VZAAoJEK8zQvxDY4P9xncH/2XKVJgyo4uEJS94XB67sOTH
QFFWRQ6YBC+jol/QO3Bm0jHYwVaOw0JppBPQ0TKKc5fNFS6XsqO+T7+IN4eHrApW
RQ31iLN/4zwI1TzAzt6QT+3IoLB5piHk7Gy/K8nfH0X1i/cBS6j+c9QtR+spbMTj
wsVs+M2++pqyxGEaPBJelQGOmbyH6hcwyLb0TfW6yhdjo00cCDjJekJLy+BvceUH
EU6kFXvR0wzmcaT7DvuhQbzFNxZJhU4dwyAjLJTkxLoxU9Hfln3qhSAi13EczY7K
5t285PGmdnE4NYJMOUE0RwQjowK3Q3lQ9otmWKmYwS1ZDwo2OIE0xrtH7z9+inw=
=oI78
-----END PGP SIGNATURE-----

Benoit Izac

non lue,
24 mai 2011, 14:58:3324/05/2011
à
Bonjour,

le 24/05/2011 à 18:22, Francois Lafont a écrit dans le message
<4ddbdb30$0$31973$426a...@news.free.fr> :

> De plus, savez comment on peut faire pour connaître le contenu de IFS
> exactement. Si je fais un echo "$IFS" > out.txt, je pense pouvoir
> deviner comme contenu « ESPACE, TAB puis \n ». Mais y a-t-il un moyen de
> voir son contenu de manière plus lisible ?

od(1)

--
Benoit Izac

Francois Lafont

non lue,
24 mai 2011, 15:02:4224/05/2011
à
Le 24/05/2011 20:13, Aéris a écrit :

>> Merci bien Aéris pour cette proposition. En fait, je pense que tu as
>> oublié de mettre un $ après la commande echo. Mais ceci est anecdotique.
>> Du coup, j'ai testé ce code :
>
> Effectivement, mais sous zsf il n'y en a pas besoin =)

zsh, plutôt ? Encore lui alors... :-)

>> #---------------------------------------------
>> echo $' aaa \n bbb ' | while IFS=$'\n' read fichier
>> do
>> echo debut---${fichier}---fin
>> done
>> #---------------------------------------------
>>
>> Et j'ai en sortie ceci :
>>
>> debut--- aaa ---fin
>> debut--- bbb ---fin
>
>
> Je n'ai pas du tout ça:

Ah bon ? Houston, j'ai un problème. Si je teste ce code (je copie-colle
sans modif, promis) :

#---------------------------------------------
#! /bin/bash

echo $' aaa \n bbb ' | while IFS=$'\n' read fichier
do
echo debut---${fichier}---fin
done
#---------------------------------------------

j'ai alors ceci (là aussi je copie-colle) :

#---------------------------------------------
$ ./test.bash


debut--- aaa ---fin
debut--- bbb ---fin

#---------------------------------------------

MAIS... si je teste tout ça *directement* en ligne de commande alors
j'ai ça :

#---------------------------------------------


$ echo $' aaa \n bbb ' | while IFS=$'\n' read fichier; do echo
"debut---${fichier}---fin"; done
debut--- aaa ---fin
debut--- bbb ---fin

#---------------------------------------------

C'est bizarre, non ? (Je suis Debian Squeeze avec bash comme shell.)

>> #---------------------------------------------
>> echo $' aaa \n bbb ' | while IFS=$'\n' && read fichier
>> do
>> echo debut---${fichier}---fin
>> done
>> #---------------------------------------------
>
> Ceci est faux.

Dans quel sens ? Au niveau syntaxique le code ne provoque aucune erreur,
enfin je crois.

> « IFS=$'\n' » n'est pas une commande mais la définition d'une variable
> d'environnement inline.

Alors vraiment je ne suis pas un spécialiste, mais est-ce qu'on peut
dire que « IFS=$'\n' » est une instruction ? Je pensais que sous bash on
pouvait mettre 2 instructions, soit sur 2 lignes, soit sur une seule
ligne mais dans ce cas on sépare les 2 instructions par un
point-virgule. Du coup, je pensais que seuls :

#----------------
IFS=$'\n'
read fichier
#----------------

ou

#----------------
IFS=$'\n' ; read fichier
#----------------

étaient valables. Mais je pensais que

#----------------
IFS=$'\n' read fichier
#----------------

était faux syntaxiquement parlant. Force m'est de constater que non.
Mais du coup, je ne comprends pas trop.

> Mais le résultat est correct quand même car la définition d'une variable
> n'échoue jamais (code de retour > 0)

Là aussi, je ne comprends pas trop. Quand une commande-instruction (?)
se déroule correctement, je pensais que le code de retour était toujours 0 ?

#----------------
$ ls
test.bash tmp

$ echo $?
0

$ ls Bureauuuuuu
ls: impossible d'accéder à Bureauuuuuu: Aucun fichier ou dossier de ce type

$ echo $?
2
#----------------

>> De plus, savez comment on peut faire pour connaître le contenu de IFS
>> exactement. Si je fais un echo "$IFS" > out.txt, je pense pouvoir
>> deviner comme contenu « ESPACE, TAB puis \n ». Mais y a-t-il un moyen de
>> voir son contenu de manière plus lisible ?
>
> echo $IFS | hexdump -C
> 00000000 20 09 0a 00 0a | ....|
> 00000005

Ok, merci pour le coup du hexdump.


--
François Lafont

Francois Lafont

non lue,
24 mai 2011, 15:12:3024/05/2011
à
Le 24/05/2011 20:58, Benoit Izac a écrit :

>> De plus, savez comment on peut faire pour connaître le contenu de IFS
>> exactement. Si je fais un echo "$IFS" > out.txt, je pense pouvoir
>> deviner comme contenu « ESPACE, TAB puis \n ». Mais y a-t-il un moyen de
>> voir son contenu de manière plus lisible ?
>
> od(1)

Merci Benoît, je ne connaissais pas.

$ cat "$IFS" > out.txt
$ od -t c out.txt
0000000 \t \n \n
0000004

Au début, je ne comprenais pas pourquoi j'ai deux fois \n, mais le
deuxième provient tout simplement de la commande echo :

$ echo "Salut" > out.txt

$ od -t c out.txt
0000000 S a l u t \n
0000006

Par contre, que représentent le 0000000 et le 0000006 ?


--
François Lafont

Aéris

non lue,
24 mai 2011, 15:35:4224/05/2011
à
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Le 24/05/2011 21:02, Francois Lafont a écrit :
> Alors vraiment je ne suis pas un spécialiste, mais est-ce qu'on peut
> dire que « IFS=$'\n' » est une instruction ?

Tout le problème est bien là.

Dans « IFS=$'\n' ; toto », c'est bien une instruction.
Dans « IFS=$'\n' toto », ça n'en est pas une.

> Je pensais que sous bash on
> pouvait mettre 2 instructions, soit sur 2 lignes, soit sur une seule
> ligne mais dans ce cas on sépare les 2 instructions par un
> point-virgule. Du coup, je pensais que seuls :
>
> #----------------
> IFS=$'\n'
> read fichier
> #----------------
>
> ou
>
> #----------------
> IFS=$'\n' ; read fichier
> #----------------
>
> étaient valables. Mais je pensais que
>
> #----------------
> IFS=$'\n' read fichier
> #----------------
>
> était faux syntaxiquement parlant. Force m'est de constater que non.
> Mais du coup, je ne comprends pas trop.

«IFS=$'\n' ; read fichier» et « IFS=$'\n'
read fichier» sont équivalents.

Mais il y a une différence entre «IFS=$'\n' ; read fichier» et
«IFS=$'\n' read fichier»

~$ FOO=bar ; test
~$ echo $FOO
bar
~$ unset FOO
~$ echo $FOO

~$ FOO=bar test
~$ echo $FOO

~$

Dans un cas la variable restera définie, dans l'autre elle n'est que
temporaire à l'appel.

>> > Mais le résultat est correct quand même car la définition d'une variable
>> > n'échoue jamais (code de retour > 0)
> Là aussi, je ne comprends pas trop. Quand une commande-instruction (?)
> se déroule correctement, je pensais que le code de retour était toujours 0 ?

Exact, erreur de ma part =)

- --
Aeris
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJN3AiIAAoJEK8zQvxDY4P9hBEH/2UoNCo9b+XDRW1WDGEr9SlM
RfLS0wfbYUBJZSyx03QKIRfdwmlSvqS07y0+BsntZYIOhq5/2qJXWYR3S41CNfW1
VwXSLwVggGJhv/wUkYOzZKYXzpQ4RdCrVW/3MLuRgy2exXmtmkJLDW9IKvZTVICX
srpWhsfzJl5/jr+FmfaqGey3QLgfxKEHexw94C+km7ovOxGwdekcBd+0DEZb1Zdv
yKqPrDSwIKSgAQAhyc3OhgdLMmjpxSzZ7pSR6qQZZH6kJshHgDspkEsdU13duw8L
uy8Mq99Tsv9fcw1nmy6XkkgZaiGfH+3vn2ObPHARYDyhPNhqDQSxd8A/IJiv5z8=
=QBB/
-----END PGP SIGNATURE-----

Aéris

non lue,
24 mai 2011, 15:51:1024/05/2011
à
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Le 24/05/2011 21:12, Francois Lafont a écrit :
> Par contre, que représentent le 0000000 et le 0000006 ?

Les numéros d'octet =)

- --
Aeris
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJN3AwoAAoJEK8zQvxDY4P99osH/0FhBskLf/mJ5pu/DXDSs1JD
mN0ngvwpLZK9CgDq88rsPoT+2NwGpgsbAxEJTxIu/wzKKUtJLNG60ev1TEwWoXKU
VSJ+YVJyKSJqmJgaPCcIgQT3gCl0jeI+BdiQgOAmZtUlKHQAEV7KZdPgyNOilv0C
FGsTZMfbFgPifqe8qNtLmAYh+nyxR6E9+Fn0O3Z63VFB+EI2IQpK/R/UkboD5EDj
t1+L+A+9OfCefdA/A+t1WjetaPhcrHagJSLNKKZvzuFLo7piu7XZKjKXv2nE0Cy8
FzOusbTwnls7SvfIOASYHcdRnV769mG9JjX3UdGqlNk+kCKaR4IHX5W74Ks0z+A=
=B7O3
-----END PGP SIGNATURE-----

Benoit Izac

non lue,
24 mai 2011, 15:57:3224/05/2011
à
Bonjour,

le 24/05/2011 à 21:12, Francois Lafont a écrit dans le message
<4ddc02f4$0$7672$426a...@news.free.fr> :

> $ cat "$IFS" > out.txt
> $ od -t c out.txt
> 0000000 \t \n \n
> 0000004

Pas besoin de passer par un fichier :
% printf $IFS | od -ta
0000000 sp ht nl nul
0000004

> $ echo "Salut" > out.txt
> $ od -t c out.txt
> 0000000 S a l u t \n
> 0000006
>
> Par contre, que représentent le 0000000 et le 0000006 ?

Le nombre d'octets lu (attention, par défaut c'est en octal).
% printf abcdefghijklmnopqrstuvwxyz | od -ta
0000000 a b c d e f g h i j k l m n o p
0000020 q r s t u v w x y z
0000032
% printf abcdefghijklmnopqrstuvwxyz | od -ta -Ad
0000000 a b c d e f g h i j k l m n o p
0000016 q r s t u v w x y z
0000026

--
Benoit Izac

Benoit Izac

non lue,
24 mai 2011, 16:21:5624/05/2011
à
Bonjour,

le 24/05/2011 à 21:02, Francois Lafont a écrit dans le message
<4ddc00a3$0$27760$426a...@news.free.fr> :

> Ah bon ? Houston, j'ai un problème. Si je teste ce code (je copie-colle
> sans modif, promis) :
>
> #---------------------------------------------
> #! /bin/bash
>
> echo $' aaa \n bbb ' | while IFS=$'\n' read fichier
> do
> echo debut---${fichier}---fin
> done
> #---------------------------------------------

Au passage, je pense que IFS='\n' peut être sans problème remplacé par
IFS= puisque par définition read ne lit qu'une ligne.

> j'ai alors ceci (là aussi je copie-colle) :
>
> #---------------------------------------------
> $ ./test.bash
> debut--- aaa ---fin
> debut--- bbb ---fin
> #---------------------------------------------

J'avoue que je ne comprends pas trop pourquoi, d'après mes tests :
bash et pdksh : debut--- aaa ---fin
dash : debut---aaa ---fin
zsh : debut--- aaa ---fin

Par contre si je modifie IFS au début du script tous fonctionnent (mais
ça pose d'autre problèmes).

--
Benoit Izac

Francois Lafont

non lue,
24 mai 2011, 16:26:5224/05/2011
à
Le 24/05/2011 21:35, Aéris a écrit :

> Tout le problème est bien là.
>
> Dans « IFS=$'\n' ; toto », c'est bien une instruction.
> Dans « IFS=$'\n' toto », ça n'en est pas une.

> ["ça" étant la partie « IFS=$'\n' »]

Mais si ce n'est pas une instruction, qu'est-ce donc alors ? En fait, si
je comprends bien l'affectation d'une variable peut avoir un statut un
peu spécial : ça peut être une instruction à part entière (c'est ce côté
là uniquement que je voyais) mais ça peut être aussi un "machin" qu'on
insère dans une instruction (je ne sais comment dire les choses
rigoureusement). C'est une sorte de spécificité du langage bash ? Par
exemple dans Python, l'affection est une instruction et c'est tout.

> «IFS=$'\n' ; read fichier» et « IFS=$'\n'
> read fichier» sont équivalents.
>
> Mais il y a une différence entre «IFS=$'\n' ; read fichier» et
> «IFS=$'\n' read fichier»
>
> ~$ FOO=bar ; test
> ~$ echo $FOO
> bar
> ~$ unset FOO
> ~$ echo $FOO
>
> ~$ FOO=bar test
> ~$ echo $FOO
>
> ~$
>
> Dans un cas la variable restera définie, dans l'autre elle n'est que
> temporaire à l'appel.

Ok, merci beaucoup, c'est très clair, j'ai bien compris la différence.
Juste un détail en passant, mais chez moi le « unset FOO » n'a pas
d'effet et la variable FOO contient toujours bar, mais ça j'imagine que
ça doit être encore une différence bash versus zsh... :-)

>> Là aussi, je ne comprends pas trop. Quand une commande-instruction (?)
>> se déroule correctement, je pensais que le code de retour était toujours 0 ?
>
> Exact, erreur de ma part =)

Pas de souci. :-)

Merci beaucoup pour tes explications. Une fois encore, j'ai appris pas
mal de trucs.


--
François Lafont

Aéris

non lue,
24 mai 2011, 16:31:5724/05/2011
à
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Le 24/05/2011 22:26, Francois Lafont a écrit :
> Ok, merci beaucoup, c'est très clair, j'ai bien compris la différence.
> Juste un détail en passant, mais chez moi le « unset FOO » n'a pas
> d'effet et la variable FOO contient toujours bar, mais ça j'imagine que
> ça doit être encore une différence bash versus zsh... :-)

Pas normal, même sous bash ça fonctionne…

- --
Aeris
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJN3BW4AAoJEK8zQvxDY4P9O6UH/Rk/PoUW6VVZZLl9/wW9zlwH
kjlHa3WOJwpBJee8N3OBTsNPDABc2YxcoGbPQU117iwkEZOrXwsvsxlol1H+fxTp
FWHi9H86rgUzxBZXuvyNVdgg72zON8kJBI7SuZKbmdhj6fKuMvIyKsiQ3VCFQLtH
b7FuhstTOx0PCjo5pXeSj5LTZidY054SDh32X3paDc77NhXd64knBo7xaV/B0wRY
xSQyhFoDJsK27E6VuFFj0i673Zi1RmTCFkeRtEVqnwGtkLxi4u3tlVDQ5h12P04l
/U4QNVPfnFRtmiNPiW3lvpUg801T7soWtN7MDt0S0490At42BDXcZ2A4Olc1bdg=
=ZjKL
-----END PGP SIGNATURE-----

Francois Lafont

non lue,
24 mai 2011, 16:33:2524/05/2011
à
Le 24/05/2011 21:57, Benoit Izac a écrit :

> Pas besoin de passer par un fichier :
> % printf $IFS | od -ta
> 0000000 sp ht nl nul
> 0000004

Ok. Par contre, c'est fou quand même les petites différences qui
s'insinuent d'un shell à un autre. Déjà, sur mon bash, ta commande ne
passe pas :

$ printf $IFS | od -ta
printf: usage: printf [-v var] format [arguments]
0000000

Mais en revanche ceci passe :

$ printf "$IFS" | od -ta
0000000 sp ht nl
0000003

Et là, même le résultat ne coïncide pas exactement avec le tien. Toi tu
as le caractère null, moi pas.

>> Par contre, que représentent le 0000000 et le 0000006 ?
>
> Le nombre d'octets lu (attention, par défaut c'est en octal).
> % printf abcdefghijklmnopqrstuvwxyz | od -ta
> 0000000 a b c d e f g h i j k l m n o p
> 0000020 q r s t u v w x y z
> 0000032
> % printf abcdefghijklmnopqrstuvwxyz | od -ta -Ad
> 0000000 a b c d e f g h i j k l m n o p
> 0000016 q r s t u v w x y z
> 0000026

Ok merci beaucoup.


--
François Lafont

Francois Lafont

non lue,
24 mai 2011, 16:38:2224/05/2011
à
Le 24/05/2011 22:21, Benoit Izac a écrit :

> J'avoue que je ne comprends pas trop pourquoi, d'après mes tests :
> bash et pdksh : debut--- aaa ---fin
> dash : debut---aaa ---fin
> zsh : debut--- aaa ---fin

C'est bien curieux.
Évidemment, si toi tu ne comprends pas, alors moi je comprends encore
moins... :-))


--
François Lafont

Benoit Izac

non lue,
24 mai 2011, 16:46:5224/05/2011
à
Bonjour,

le 24/05/2011 à 22:33, Francois Lafont a écrit dans le message
<4ddc15e5$0$19682$426a...@news.free.fr> :

>> Pas besoin de passer par un fichier :
>> % printf $IFS | od -ta
>> 0000000 sp ht nl nul
>> 0000004
>
> Ok. Par contre, c'est fou quand même les petites différences qui
> s'insinuent d'un shell à un autre. Déjà, sur mon bash, ta commande ne
> passe pas :
>
> $ printf $IFS | od -ta
> printf: usage: printf [-v var] format [arguments]
> 0000000

Oui, c'est normal ; depuis le temps que je me dis qu'il faut que
j'arrête de faire mes tests directement sous zsh... D'un autre coté sous
dash, bien que le plus proche de POSIX, c'est un peu la galère : pas de
complétion, pas d'historique.

> Mais en revanche ceci passe :
>
> $ printf "$IFS" | od -ta
> 0000000 sp ht nl
> 0000003
>
> Et là, même le résultat ne coïncide pas exactement avec le tien. Toi tu
> as le caractère null, moi pas.

C'est zsh, hein, quand on te dit qu'il est plus fort que les autres, ce
n'est pas pour rien. ;)

--
Benoit Izac

Francois Lafont

non lue,
24 mai 2011, 16:48:4924/05/2011
à
Le 24/05/2011 22:31, Aéris a écrit :

> Le 24/05/2011 22:26, Francois Lafont a écrit :
>> Ok, merci beaucoup, c'est très clair, j'ai bien compris la différence.
>> Juste un détail en passant, mais chez moi le « unset FOO » n'a pas
>> d'effet et la variable FOO contient toujours bar, mais ça j'imagine que
>> ça doit être encore une différence bash versus zsh... :-)
>
> Pas normal, même sous bash ça fonctionne…

Oui, oui ! Là, c'est moi qui fatigue. Ça fonctionne très bien. Au temps
pour moi.

Je viens de m'apercevoir qu'il y a un autre truc sur lequel j'ai craqué
(je crois qu'il faut que j'aille me couché).

J'avais dit que je n'avais pas le même résultat entre ça :

#---------------------------------------------
#! /bin/bash

echo $' aaa \n bbb ' | while IFS=$'\n' read fichier
do
echo debut---${fichier}---fin
done
#---------------------------------------------

et le script directement en ligne commande comme ça :

$ echo $' aaa \n bbb ' | while IFS=$'\n' read fichier; do echo
debut---${fichier}---fin; done

Je ne sais pas ce qu'il m'a pris, mais heureusement, j'ai bien le même
résultat dans les deux cas, à savoir ceci :

debut--- aaa ---fin
debut--- bbb ---fin

(Qui n'est pas le résultat souhaité mais bon...)

--
François Lafont

Benoit Izac

non lue,
24 mai 2011, 17:11:1424/05/2011
à
Bonjour,

le 24/05/2011 à 22:26, Francois Lafont a écrit dans le message
<4ddc145c$0$4781$426a...@news.free.fr> :

>> Dans « IFS=$'\n' ; toto », c'est bien une instruction.
>> Dans « IFS=$'\n' toto », ça n'en est pas une.
>> ["ça" étant la partie « IFS=$'\n' »]
>
> Mais si ce n'est pas une instruction, qu'est-ce donc alors ?

Une modification de l'environnement de la commande qui suit. Un petit
exemple :

% cat getenv.c
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char *v = getenv("ma_variable");
if (v != NULL)
printf("%s\n", v);
else
printf("ma_variable n'existe pas\n");
return 0;
}
% cc -o getenv getenv.c
% ./getenv
ma_variable n'existe pas
% ma_variable=abc ./getenv
abc
% ma_variable=xyz
% ./getenv
ma_variable n'existe pas
% export ma_variable
% ./getenv
xyz
% ma_variable=abc ./getenv
abc
% ./getenv
xyz
% unset ma_variable
% ./getenv
ma_variable n'existe pas

--
Benoit Izac

Francois Lafont

non lue,
26 mai 2011, 07:51:3826/05/2011
à
Le 24/05/2011 23:11, Benoit Izac a écrit :


>>> Dans « IFS=$'\n' ; toto », c'est bien une instruction.
>>> Dans « IFS=$'\n' toto », ça n'en est pas une.
>>> ["ça" étant la partie « IFS=$'\n' »]
>>
>> Mais si ce n'est pas une instruction, qu'est-ce donc alors ?
>
> Une modification de l'environnement de la commande qui suit. Un petit
> exemple :
>

> [couic]


Merci beaucoup Benoît pour cet exemple super clair.

--
François Lafont

Francois Lafont

non lue,
30 mai 2011, 08:55:1930/05/2011
à
Bonjour à tous,

Désolé de remonter ce fil usé jusqu'à la corde, mais il y avait encore
un point non résolu avec ce simple code :

#------------------------------------------------
echo $' 3espacesPuis2 \n 1espacesPuis4 ' | while IFS=$'\n' read
fichier
do
echo debut---$fichier---fin
done
#------------------------------------------------

Sous bash (Debian Squeeze pour moi), il ne donne pas le résultat
attendu. En effet, il donne :

debut--- 3espacesPuis2 ---fin
debut--- 1espacesPuis4 ---fin

Alors qu'on attendait :

debut--- 3espacesPuis2 ---fin
debut--- 1espacesPuis4 ---fin

(Au passage, le code donne le résultat attendu sous zsh d'après ceux qui
ont testé.)

Je viens de remarquer que si on mettait des doubles quotes autour de la
variable fichier ainsi :

#------------------------------------------------
echo $' 3espacesPuis2 \n 1espacesPuis4 ' | while IFS=$'\n' read
fichier
do
echo debut---"$fichier"---fin
done
#------------------------------------------------

Alors on avait bien le fameux résultat attendu, à savoir :

debut--- 3espacesPuis2 ---fin
debut--- 1espacesPuis4 ---fin

Avez-vous des explications ? J'ai l'impression que ça ressemble à une
histoire de timing d'expansion de variable, un peu comme on peut en
rencontrer en TeX/LaTeX mais je me trompe peut-être.

En tout cas, je me rappelle qu'Aéris avec pour habitude d'appeler
systématiquement ses variables ${variable} et bien je crois que je vais
prendre l'habitude de les appeler "$variable".


--
François Lafont

Benoit Izac

non lue,
30 mai 2011, 14:14:0430/05/2011
à
Bonjour,

le 30/05/2011 à 14:55, Francois Lafont a écrit dans le message
<4de39384$0$17768$426a...@news.free.fr> :

> Je viens de remarquer que si on mettait des doubles quotes autour de la
> variable fichier ainsi :
>
> #------------------------------------------------
> echo $' 3espacesPuis2 \n 1espacesPuis4 ' | while IFS=$'\n' read
> fichier
> do
> echo debut---"$fichier"---fin
> done
> #------------------------------------------------
>
> Alors on avait bien le fameux résultat attendu, à savoir :
>
> debut--- 3espacesPuis2 ---fin
> debut--- 1espacesPuis4 ---fin
>
> Avez-vous des explications ? J'ai l'impression que ça ressemble à une
> histoire de timing d'expansion de variable, un peu comme on peut en
> rencontrer en TeX/LaTeX mais je me trompe peut-être.

Bon, je crois que j'ai trouvé l'explication dans la page man de bash
sous « Word Splitting » ou dans SUSv3 :
<http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_05>

Tests fait avec bash :


$ printf "$IFS" | od -ta
0000000 sp ht nl
0000003

$ a=' abcd '
$ echo ,$a,
, abcd ,
$ IFS=''
$ echo ,$a,
, abcd ,
$ unset IFS
$ echo ,$a,
, abcd ,
$ IFS='b'
$ echo ,$a,
, a cd ,

> En tout cas, je me rappelle qu'Aéris avec pour habitude d'appeler
> systématiquement ses variables ${variable} et bien je crois que je vais
> prendre l'habitude de les appeler "$variable".

C'est clairement conseillé.

--
Benoit Izac

Lucas Levrel

non lue,
31 mai 2011, 08:51:2231/05/2011
à
Aéris :

>>>> Dans « IFS=$'\n' ; toto », c'est bien une instruction.
>>>> Dans « IFS=$'\n' toto », ça n'en est pas une.
>>>> ["ça" étant la partie « IFS=$'\n' »]

François :


>>> Mais si ce n'est pas une instruction, qu'est-ce donc alors ?

Benoit :


>> Une modification de l'environnement de la commande qui suit. Un petit
>> exemple :

Le 26 mai 2011, Francois Lafont a écrit :
> Merci beaucoup Benoît pour cet exemple super clair.


Pour en mettre une dernière couche, j'ajouterais que IFS n'est pas
normalement une variable d'environnement, c'est juste une variable du
shell (comme ma_variable dans l'exemple de Benoît avant qu'on fasse
« export ma_variable ») ; voir Shell Variables dans man bash.

Donc pour un toto quelconque il n'est pas correct de faire
> IFS=truc toto $arguments
car ça n'aura pas d'effet sur le découpage des arguments. Exemple :
> var=atata
> IFS=t echo $var
atata
> IFS=t
> echo $var
a a a
Bien sûr, ici toto c'est read, un bash-builtin qui précisément utilise
la valeur que possède IFS dans son environnement.

--
LL

Francois Lafont

non lue,
3 juin 2011, 10:37:1003/06/2011
à
Bonjour,

Merci de ta réponse Benoît et désolé de ma réponse tardive mais j'ai mis
un peu de temps à comprendre tout ça.

Le 30/05/2011 20:14, Benoit Izac a écrit :

> Bon, je crois que j'ai trouvé l'explication dans la page man de bash
> sous « Word Splitting » ou dans SUSv3 :
> <http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_05>

Effectivement, le « word splitting » semble être l'explication de tout
ça. Ce que j'ai retenu après lecture du «man bash», c'est que :

a) Le « word splitting » a lieu après l'expansion des paramètres $parametre.

b) Quand une expression est entre des doubles quotes, le « word
splitting » n'a pas lieu et le contenu est considéré comme un seul mot
ou comme une partie d'un mot (comme dans « "a""bb cc" » qui est vu
comme un seul mot).

c) La commande echo affiche les mots qui lui sont passés en paramètre
(une fois que le « word splitting » a eu lieu ou pas) en les séparant
par des caractères espace.

Si je résume, dans le code suivant :

--8<----8<----8<----8<----8<----8<----8<----8<--
#! /bin/bash
echo -n $'a a\n b \n c c \n' | while IFS=$'\n' read f
do
echo \|"$f"\|
done
--8<----8<----8<----8<----8<----8<----8<----8<--

1) IFS=$'\n' est nécessaire car la commande read va mettre dans la
variable f l'ensemble des mots (avec leurs séparateurs) qu'elle reçoit
en entrée sur une ligne une fois que celle-ci ait subi le fameux « word
splitting ». Sans IFS=$'\n', après la lecture de la ligne
«<SPACE><SPACE><SPACE>b<SPACE><SPACE><SPACE>\n», read stockerait juste
«b» dans la variable f car le « word splitting » aura fait son œuvre et
<SPACE><SPACE>b<SPACE><SPACE><SPACE>\n» sera vu comme le mot «b».

2) Les doubles quotes sont nécessaires dans la commande echo car, là
aussi, sans celles-ci, après expansion du paramètre $f, ceux qu'il a
après echo subit aussi le « word splitting » et donc, comme echo affiche
tous les mots qu'il reçoit en argument en les séparant par des espace,
on aurait un comme résultat :

|a a|
| b |
| c c |

Avec les doubles quotes, le « word splitting » ne se fait pas et donc
echo se retrouve avec un seul mot en argument ce qui donne l'affichage
voulu.


--
François Lafont

Francois Lafont

non lue,
3 juin 2011, 10:50:5003/06/2011
à
Le 31/05/2011 14:51, Lucas Levrel a écrit :

> Pour en mettre une dernière couche, j'ajouterais que IFS n'est pas
> normalement une variable d'environnement, c'est juste une variable du
> shell (comme ma_variable dans l'exemple de Benoît avant qu'on fasse
> « export ma_variable ») ; voir Shell Variables dans man bash.

Ok, c'est une variable d'environnement pour le shell bash uniquement.

> Donc pour un toto quelconque il n'est pas correct de faire

> $ IFS=truc toto $arguments


> car ça n'aura pas d'effet sur le découpage des arguments. Exemple :

> $ var=atata
> $ IFS=t echo $var
> atata

Je comprends très bien ce que tu veux dire, mais il me semble que
l'exemple n'est pas bien choisi ici car echo est justement une primitive
du bash. Donc on aurait pu s'attendre à ce qu'elle soit sensible à IFS.

> $ IFS=t
> $ echo $var
> a a a

Mais echo a l'air particulièrement bizarre. Comment expliquer ceci ?

(Sous Bash donc)
$ IFS="B"
$ echo aBaBa
aBaBa

Bizarre, non ? J'ai l'impression que echo, toute bash-builtin qu'elle
puisse être, est en fin de compte totalement insensible à IFS et que
c'est au moment l'expansion de paramètres que IFS joue un rôle car par
contre j'ai bien :

$ IFS="B"
$ var="aBaBa"
$ echo $var
a a a

Mais sur ce point, je n'ai pas réussi à trouver une explication dans le
manual.

> Bien sûr, ici toto c'est read, un bash-builtin qui précisément utilise
> la valeur que possède IFS dans son environnement.

Oui, il est clairement indiqué dans « man bash » que read fait usage de
IFS pour le « word splitting ». Pour echo, c'est beaucoup moins clair je
trouve...


--
François Lafont

Benoit Izac

non lue,
3 juin 2011, 15:59:2303/06/2011
à
Bonjour,

le 03/06/2011 à 16:50, Francois Lafont a écrit dans le message
<4de8f48c$0$1188$426a...@news.free.fr> :

echo se moque d'IFS par contre il renvoie les arguments en les séparant
par un espace :
$ echo a b c d
a b c d

Dans ton exemple ci-dessus, $var est transformé en « a a » avant d'être
passer en argument à echo. Un « set -x » te le montre clairement :
$ set -x
$ IFS=B
+ IFS=B
$ var=aBaB
+ var=aBaB
$ echo $var
+ echo a a
a a


J'ai l'impression que ce que tu n'as pas compris, c'est que le « word
splitting » ne s'applique pas pour echo ou read (bien que ce soit
similaire car read utilise aussi $IFS). Reprenons la page de manuel de
bash :

Word Splitting
The shell scans the results of parameter expansion, command substitu‐
tion, and arithmetic expansion that did not occur within double quotes
for word splitting.

Soit seulement trois cas sont concernés pour le « word splitting » :

parameter expansion, c'est ce que l'on appelle communément une variable
$var qui peux éventuellement être transformé avant : ${var#a}, etc.

command substitution, c'est pour récupérer la sortie d'une commande :
$(ifconfig eth0)

arithmetic expansion, c'est pour les calculs : $((30+12))

--
Benoit Izac

Francois Lafont

non lue,
3 juin 2011, 17:55:2603/06/2011
à
Le 03/06/2011 21:59, Benoit Izac a écrit :

> echo se moque d'IFS par contre il renvoie les arguments en les séparant
> par un espace :
> $ echo a b c d
> a b c d

Ok.

> Dans ton exemple ci-dessus, $var est transformé en « a a » avant d'être
> passer en argument à echo. Un « set -x » te le montre clairement :
> $ set -x
> $ IFS=B
> + IFS=B
> $ var=aBaB
> + var=aBaB
> $ echo $var
> + echo a a
> a a

Je retiens le coup du set -x.

> J'ai l'impression que ce que tu n'as pas compris, c'est que le « word
> splitting » ne s'applique pas pour echo ou read (bien que ce soit
> similaire car read utilise aussi $IFS). Reprenons la page de manuel de
> bash :

Tu as raison, je n'avais pas bien compris cela. Mais quand tu dis que
read ne fait pas de « word spitting », je ne suis pas tout à fait
d'accord car on lit dans le manuel « The characters in IFS are used
to split the line into words ». Du coup, j'ai un peu envie d'appeler ça
du « word splitting ». Ceci dit, tu nuances tes propos avec ce que tu
mets entre parenthèses du coup, là c'est peut-être juste une histoire de
terminologie.

> Soit seulement trois cas sont concernés pour le « word splitting » :
>
> parameter expansion, c'est ce que l'on appelle communément une variable
> $var qui peux éventuellement être transformé avant : ${var#a}, etc.
>
> command substitution, c'est pour récupérer la sortie d'une commande :
> $(ifconfig eth0)
>
> arithmetic expansion, c'est pour les calculs : $((30+12))

Ok, merci de me "recadrer". Du coup, j'ai juste du mal à comprendre au
final ce qui délimite les *arguments* d'une commande. Si je comprends
bien IFS n'a rien à voir là dedans (sauf si bien sûr on tombe sur un des
3 cas que tu m'as rappelés ci-dessus). Je pensais que les doubles quotes
permettaient de délimiter des arguments mais par exemple dans ceci :

$ set -x
$ echo "a""bb"
+ echo abb
abb

Je pensais que "a""bb" formait 2 arguments et en fin de compte il n'en
forme qu'un. Donc au final, quelle règle s'applique pour la délimitation
d'arguments d'une commande ?


--
François Lafont

Benoit Izac

non lue,
3 juin 2011, 19:14:3103/06/2011
à
Bonjour,

le 03/06/2011 à 23:55, Francois Lafont a écrit dans le message
<4de9580d$0$3962$426a...@news.free.fr> :

>> J'ai l'impression que ce que tu n'as pas compris, c'est que le « word
>> splitting » ne s'applique pas pour echo ou read (bien que ce soit
>> similaire car read utilise aussi $IFS). Reprenons la page de manuel de
>> bash :
>
> Tu as raison, je n'avais pas bien compris cela. Mais quand tu dis que
> read ne fait pas de « word spitting », je ne suis pas tout à fait
> d'accord car on lit dans le manuel « The characters in IFS are used
> to split the line into words ». Du coup, j'ai un peu envie d'appeler ça
> du « word splitting ». Ceci dit, tu nuances tes propos avec ce que tu
> mets entre parenthèses du coup, là c'est peut-être juste une histoire de
> terminologie.

Découper un mot et découper en mots, ce n'est pas exactement pareil. Le
rôle de read, qui dans les exemples précédent servaient à lire une
ligne, est plus généralement :
$ echo 'un deux trois quatre' | {
read a b c
printf '$a=%s $b=%s $c=%s\n' "$a" "$b" "$c"
}
$a=un $b=deux $c=trois quatre

J'anticipe avant que tu ne poses la question, tu ne peux pas faire :
$ echo 'un deux trois quatre' | read a b c
$ # ensuite utiliser $a $b $c
car le read va être exécuté dans un sous-shell (sauf avec zsh) et du
coup le père n'a pas accès à ces variables (on en a déjà parlé il
y a quelque temps si je me souviens bien).

> [...]


> $ set -x
> $ echo "a""bb"
> + echo abb
> abb
>
> Je pensais que "a""bb" formait 2 arguments et en fin de compte il n'en
> forme qu'un. Donc au final, quelle règle s'applique pour la délimitation
> d'arguments d'une commande ?

Quand tu écris "a""bb", le shell retire les « " », il ne reste plus que
abb comme le montre le set -x ci-dessus. C'est les blancs (espaces et
tabulations) qui délimitent les arguments (Simple Commands dans la page
de manuel de bash) :

$ cat arg.c
#include <stdio.h>
int main(int argc, char *argv[])
{
int i = 0;
printf("il y a %d arguments\n", argc - 1);
while (i++ < argc - 1)
printf("arg %2d: _%s_\n", i, argv[i]);
return 0;
}
$ cc -o arg arg.c
$ ./arg a b c\ d "ee"f 'g h'i k # tabulation entre i et k
il y a 6 arguments
arg 1: _a_
arg 2: _b_
arg 3: _c d_
arg 4: _eef_
arg 5: _g hi_
arg 6: _k_

--
Benoit Izac

Francois Lafont

non lue,
3 juin 2011, 20:05:4203/06/2011
à
Le 04/06/2011 01:14, Benoit Izac a écrit :

> Découper un mot et découper en mots, ce n'est pas exactement pareil. Le
> rôle de read, qui dans les exemples précédent servaient à lire une
> ligne, est plus généralement :
> $ echo 'un deux trois quatre' | {
> read a b c
> printf '$a=%s $b=%s $c=%s\n' "$a" "$b" "$c"
> }
> $a=un $b=deux $c=trois quatre
>
> J'anticipe avant que tu ne poses la question, tu ne peux pas faire :
> $ echo 'un deux trois quatre' | read a b c
> $ # ensuite utiliser $a $b $c

J'apprécie ce geste d'empathie ;-) mais jamais je ne t'aurais posé la
question car 1) comme tu le signales nous en avons déjà parlé sur ce
forum et 2) je garde soigneusement la trace de toutes mes discussions
sur les forums de news, et même parfois, quand j'en ai le temps et que
j'estime avoir bien compris la chose, je m'en fais un petit article sur
mon «blog perso» qui me sert uniquement de mémento personnel (pour les
articles, je me limite à ce qui touche à Linux).

> Quand tu écris "a""bb", le shell retire les « " », il ne reste plus que
> abb comme le montre le set -x ci-dessus. C'est les blancs (espaces et
> tabulations) qui délimitent les arguments (Simple Commands dans la page
> de manuel de bash) :

Oui il est bien dit que ce sont les blancs qui délimitent les arguments.
Mais cela me semble très réducteur, car les doubles quotes ou les
simples quotes sont aussi des délimiteurs (il me semble) et je n'arrive
pas à y trouver mention dans le manuel. Par exemple :

echo "a" "b b" # 2 arguments
echo a b b # 3 arguments.

Pour moi, ce ne sont pas seulement les blancs qui délimitent les
arguments, les quotes jouent un rôle important.


--
François Lafont

Benoit Izac

non lue,
4 juin 2011, 02:15:1004/06/2011
à
Bonjour,

le 04/06/2011 à 02:05, Francois Lafont a écrit dans le message
<4de97694$0$4173$426a...@news.free.fr> :

> Oui il est bien dit que ce sont les blancs qui délimitent les arguments.
> Mais cela me semble très réducteur, car les doubles quotes ou les
> simples quotes sont aussi des délimiteurs (il me semble) et je n'arrive
> pas à y trouver mention dans le manuel. Par exemple :
>
> echo "a" "b b" # 2 arguments
> echo a b b # 3 arguments.

echo a b\ \ b # 2 arguments

> Pour moi, ce ne sont pas seulement les blancs qui délimitent les
> arguments, les quotes jouent un rôle important.

Ils (Elles ?) jouent un rôle mais pas celui de délimiteur :

QUOTING
Quoting is used to remove the special meaning of certain characters or
words to the shell. Quoting can be used to disable special treatment
for special characters, to prevent reserved words from being recognized
as such, and to prevent parameter expansion.

--
Benoit Izac

Francois Lafont

non lue,
4 juin 2011, 08:39:3604/06/2011
à
Le 04/06/2011 08:15, Benoit Izac a écrit :

>> echo "a" "b b" # 2 arguments
>> echo a b b # 3 arguments.
>
> echo a b\ \ b # 2 arguments
>
>> Pour moi, ce ne sont pas seulement les blancs qui délimitent les
>> arguments, les quotes jouent un rôle important.
>
> Ils (Elles ?) jouent un rôle mais pas celui de délimiteur :
>
> QUOTING
> Quoting is used to remove the special meaning of certain characters or
> words to the shell. Quoting can be used to disable special treatment
> for special characters, to prevent reserved words from being recognized
> as such, and to prevent parameter expansion.

Ok, les (doubles) quotes enlèvent aux (à certains) caractères spéciaux
leur signification et par exemple l'espace qui est un caractère spécial
servant à délimiter les mots devient un caractère comme un autre quand
il est entre (doubles) quotes.

Encore une fois, merci beaucoup Benoit pour toutes tes explications.
A+

--
François Lafont

0 nouveau message