Re: Lidt korn shell scripting [array]

From: Lasse H.Petersen (none@lhp--toft-hp.dk.lh.bsd-dk.dk)
Date: Thu 06 Oct 2005 - 19:41:54 CEST


To: per engelbrecht <none@per--xterm.dk.lh.bsd-dk.dk>, bsd-dk@bsd-dk.dk
From: Lasse H.Petersen <none@lhp--toft-hp.dk.lh.bsd-dk.dk>
Subject: Re: Lidt korn shell scripting [array]
Date: Thu,  6 Oct 2005 19:41:54 +0200 (CEST)

Per skrev:

(Dennis skrev:)
>> find . -type f -name "*.$tld[*]" -print | while

Det vil ikke kunne virke.

>#! /bin/ksh
>#
># Update snumber recursive in all zone files, copy zonefiles and append
>#.internal to all new files.
># PE
>#
>
>v1='com'
>v2='net'
>v3='dk'
>v4='de'
>v5='se'
>v6='nl'
>v7='ru'
>
>find . -type f -name "*.$v*" -print | while read i

Det virker heller ikke, af samme årsag, men kunne evt se ud som om det gjorde!

able:~ $ cat test.ksh
v1='com'
v2='net'
v3='dk'
v4='de'
v5='se'
v6='nl'
v7='ru'

echo . -type f -name "*.$v*" -print

able:~ $ ksh test.ksh
. -type f -name *.* -print

Da du ikke applikerer nogen eval, expanderer du bare en ikke-eksisterende
variabel $v (til en tom streng) og sætter "*." foran og "*" bagved. Det
er også et fint argument til find, som bare finder alle filer med "." i
navnet. Formentlig flere end du ville have. Så hvis du har kørt det script,
har du forhåbentlig en backup at falde tilbage på, eller en anden udvej.

Det du *vil* er så vidt jeg kan se at producere en find som på en gang
traverserer dit træ og finder alle filer der ender på et af de angivne TLDer,
så du ikke skal traversere hele træet en gang for hver TLD.

find er et program, og det kender ikke noget til ksh-variable eller arrays. De
bliver expanderet af shellen. Shellen expanderer også wildcard "*" med mindre
intet matcher. (Prøv selv:
echo *
giver filerne i current dir
echo *.duharingenfilveddettenavn
giver
*.duharingenfilveddettenavn)

I stedet har find mulighed for at bruge komplekse udtryk som argument, udtryk
som den selv fortolker. se find(1) i TFM.

Så du har brug for dette:
echo $(for i in com net dk de se nl ru ; \
do echo -name "*.$i" -print -o ; done) -type f -prune

for at lave den parameterliste som du faktisk vil bruge til find.
(Det sidste -type f -prune er blot mit bedste bud på en no-op for at
kunne printe et overskydende -o uden problemer.)

Der er eet problem, ovenstående virker kun hvis der ikke er noget i current
directory som matcher - jf det om wildcard ovenfor. Skriver man i stedet
"\*.$i", så får find desværre backslashen med. Jeg kan ikke lige gennemskue
hvordan man undgår det problem. Quotes i shell er generelt lidt tricky.
En mulighed er at lave et tomt dir, hoppe ind i det og så bruge find ..:
mkdir .foo.$$
cd .foo.$$
find .. $(for i in com net dk de se nl ru ; \
do echo -name "*.$i" -print -o ; done) -type f -prune|while read f ; do ...
done
cd .. ; rmdir .foo.$$

(Man kan selvfølgelig bruge en anden sti end .. som første argument til
find, pointen at der hvor man *står* må der ikke være noget der matcher.)

Hvis der er nogen der ved hvordan man skal sætte nogle quotes i $(...)
udtrykket så det virker rigtigt, vil jeg gerne se det!

Alternativt ville jeg nok bruge en anelse Perl i stedet. Eller simpelthen
bare:

find . -type f |grep -E '\.(com|net|dk|de|se|nl|ru)$'|while read f ; do ...
done

(Jeg håber det var til en smule hjælp for dig eller andre!)

-Lasse



This archive was generated by hypermail 2b30 : Wed 15 Nov 2006 - 18:24:53 CET