File-ok rekurzív listázása

Fórumok

File-ok rekurzív listázása

Hozzászólások

Egy scriptben szeretném feldolgoztatni egy könyvtár összes állományát. Ehhez kellene valami, ami készít egy teljes (rekurzív) listát a könyvtár fájljairól az abszolút úttal együtt. Persze az 'ls -aR' tűnik a legkézenfekvőbbnek, de ez nem produkál olyan kimenetet, amit egyszerűen fel lehetne dolgozni:
[code:1:facae4aca6]./.evolution:
. addressbook calendar cert8.db mail tasks
.. cache camel-cert.db key3.db secmod.db

./.evolution/addressbook:
. .. local

./.evolution/addressbook/local:
. .. system

./.evolution/addressbook/local/system:
. .. addressbook.db addressbook.db.summary

./.evolution/cache:
. ..

./.evolution/calendar:
. .. config local
[/code:1:facae4aca6]

[quote:db2da92804="norcrys"]Ehhez kellene valami, ami készít egy teljes (rekurzív) listát a könyvtár fájljairól az abszolút úttal együtt.

find

Első blikkre ez:
[code:1:629e7208fd]
find . -exec rm {} \;
[/code:1:629e7208fd]
vagy
[code:1:629e7208fd]find . > filelista.txt[/code:1:629e7208fd]

Na, ez egyszerűbb, mint gondoltam. Féltem, hogy túl triviális lesz, de bonyolult scriptet simán megírtam, a find meg nem jutott eszembe. :oops:

for list in *; do echo $list; done

...és akkor külső programot sem kell meghívni. :wink:

[quote:2362cd0c97="hunger"]for list in *; do echo $list; done

...és akkor külső programot sem kell meghívni. :wink:

Ez szuper. Erre sem gondoltam, végig az ls kimenete bosszantott. :evil:

Jah, közben leesett, hogy rekurzívan kellene végigmenni az alkönyvtárokon is. Persze akkor sem olyan nagy ügy.

Első körben én valami ilyesmire gondoltam:

rekurzio() { for list in *; do if test -d "$list"; then cd "$list"; rekurzio; cd ..; else echo $list; fi; done; }; rekurzio;

Nem teljesen tökéletes, mert a kötőjellel kezdődő könyvtárneveket és egyéb érdekességeket nem kezeli le rendesen, de kiindulásnak szerintem megfelelő.

[quote:37848232f1="hunger"]Jah, közben leesett, hogy rekurzívan kellene végigmenni az alkönyvtárokon is. Persze akkor sem olyan nagy ügy.

Első körben én valami ilyesmire gondoltam:

rekurzio() { for list in *; do if test -d "$list"; then cd "$list"; rekurzio; cd ..; else echo $list; fi; done; }; rekurzio;

Nem teljesen tökéletes, mert a kötőjellel kezdődő könyvtárneveket és egyéb érdekességeket nem kezeli le rendesen, de kiindulásnak szerintem megfelelő.

Ezzel csak az a baj, hogy a "cd" miatt relatív fájlneveket ír*, valamint sokkal lassabb a find-nál**, de az ötlet jó :)
Meg utálom a rekurziót, múltkor is memória hibát követett el egy rekurzív függvényem, pedig nem hagytam túlcsordulni.

*igaz, ezt lehet orvosolni
**ez meg csak kötözködés

A 'for i in *;'-gal csak óvatosan, mert ugye a csillagot shell bontja ki, és pár tízezer file esetén simán feladja az osztályharcot, hasonlóan az 'rm *' is megmakkan tőle, csak itt nem a lista, hanem a parancssor lesz túl hosszú. Eddigi tapasztalataim szerint a 'find . -type f -exec rm {} \;' a leghatékonyabb, bár kicsit időigényes, hogy a file-okra egyesével indítgatja az rm-et.

[quote:bec47a5a42="gsimon"]find . -type f -exec rm {} \;

Ennél sokkal jobb:
find . -type f | xargs rm
illetve az abszolút atombiztos változat ami helyesen kezel minden extrém fájlnevet:
find . -type f -print0 | xargs -0 -r rm --
Az xargs lényege, hogy egy rm parancsra annyi fájlt rábíz, amilyen hosszú csak lehet a parancssor, tehát megtalálja az arany középutat a fájlonként külön processz és a túl hosszú argumentumlista miatti elhasalás között.

[quote:526c5e670e="egmont"]
illetve az abszolút atombiztos változat ami helyesen kezel minden extrém fájlnevet:
find . -type f -print0 | xargs -0 -r rm --

ezt koszi, eddig meg nem dobbentem ra, hogy a -print0 milyen hasznos a find-ben:)

Na, ez a perl kód meghozta a kódolási kedvemet is. Akkor legyen itt a működő python kód (eddig még nem szállt el). Ez is nagyon egyszerű.
[code:1:06a0277eef]#!/usr/bin/python

import sys, os, os.path

def rekurziv_filecseszegeto(directory):
filenames = os.listdir(directory)
dirname = os.path.dirname(directory)
for filename in filenames:
fname = dirname + "/" + filename
if os.path.isdir(fname):
rekurziv_filecseszegeto(fname + "/")
// ..... feldolgozás...

rekurziv_filecseszegeto(sys.argv[1])
[/code:1:06a0277eef]

Ja, és mennyivel áttekinthetőbb, mint a perl... Na, ezért is szeressük a (Monthy) Pythont. 8)

Ehe, ez hihetetlen :)
Ma este szivtam a dologgal, meg is csináltam a magam módján, pedig elég lett volna ezt a fórumot felkeresni :)
Az én megoldásom:

[code:1:d635db9c5f]ls -R "/mnt" | awk \
'{if($0~/.+/)
{if($0~/^\/mnt/) {d=substr($0,0, length($0)-1)"/";}
else {print d$0} } }'
[/code:1:d635db9c5f]

[quote:e7c9338d63="egmont"][quote:e7c9338d63="gsimon"]find . -type f -exec rm {} \;

Ennél sokkal jobb:
find . -type f | xargs rm
illetve az abszolút atombiztos változat ami helyesen kezel minden extrém fájlnevet:
find . -type f -print0 | xargs -0 -r rm --
Az xargs lényege, hogy egy rm parancsra annyi fájlt rábíz, amilyen hosszú csak lehet a parancssor, tehát megtalálja az arany középutat a fájlonként külön processz és a túl hosszú argumentumlista miatti elhasalás között.

Az első változat felejtendő. Egy rendes, UTF-8 kódolású könyvtárszerkezetre is sír már, hogy idétlen a fájlnév. A másodikat nem próbáltam.

csak hogy a ruby se maradjon ki...
(megj.: a listázandó könyvtár nevét az első paraméteren kell átadni, pl "./prog /usr/local/", alapból a /tmp-t listázza)
(megj2.: futtatáshoz miután chmod +x -elve lett, pipeold be mondjuk egy xargs-ba és a xargs után jöhet a parancs neve amelyiket végre akarod hajtani mindegyik fileon)

[code:1:81562bd1c1]
#!/usr/bin/ruby

require 'find'

rdir = ARGV[0] || "/tmp"

Find.find(rdir) do |path|
if FileTest.directory?(path)
next
else
puts path
end
end
[/code:1:81562bd1c1]

[quote:73c40c69ce="egmont"][quote:73c40c69ce="gsimon"]find . -type f -exec rm {} \;

Ennél sokkal jobb:
find . -type f | xargs rm
illetve az abszolút atombiztos változat ami helyesen kezel minden extrém fájlnevet:
find . -type f -print0 | xargs -0 -r rm --
Az xargs lényege, hogy egy rm parancsra annyi fájlt rábíz, amilyen hosszú csak lehet a parancssor, tehát megtalálja az arany középutat a fájlonként külön processz és a túl hosszú argumentumlista miatti elhasalás között.

Na, nem is gondoltam, hogy ennyire tudjuk variálni a témát :)
Köszi, ezt ki is próbálom.

Amúgy eredetileg python kezelné le a témát, de nagy "létszámú", sok rekurzív hívást igénylő foldereknél előrejelezhetetlen módon memóriahibával elszáll.

[quote:ecb1344a2f="norcrys"]
Na, nem is gondoltam, hogy ennyire tudjuk variálni a témát :)
Köszi, ezt ki is próbálom.

Amúgy eredetileg python kezelné le a témát, de nagy "létszámú", sok rekurzív hívást igénylő foldereknél előrejelezhetetlen módon memóriahibával elszáll.

na meg egy megoldas. nem python kell, hanem perl:)

[code:1:ecb1344a2f]
#!/usr/bin/perl
sub whichfiles {
local $fullname= "$File::Find::name";
$_=$fullname;
-f $fullname && !/jpg$/ && do {
local $res = normalizer("", $fullname);
if ("$fullname" ne "$res") {
# print "$fullname\t=>\t$res\n" ;
rename($fullname,$res);
}
}
}

find(\&whichfiles, "$ARGV[0]" );
[/code:1:ecb1344a2f]

ARGV[0]-ban konyvtarnevet var teljes path-al, ha file, es nem jpg-re vegzodik, akkor dolgozik:)
Az esetek donto tobbsegeben joval gyorsabb, mint a shell-es find