sziasztok
nem nagyon értek a szkriptekhez, az alábbit tákoltam össze, de szeretném kérni, segítsetek, hogyan lehetne optimalizálni gyorsabb futásra. (gondolom, kevesebb "fork" meg pipe, stb.)
jelenleg a duplikátumok keresése (a while ciklusban) sokkal tovább tart, mint az md5 kalkulálása... ami azért elég gáz :)
ez volna az
előre is kösz a segítséget!
- 1691 megtekintés
Hozzászólások
#
while read line; do
_SUM2=`echo "$line" | awk '{print $1}'`
_PATH2=`echo "$line" | awk '{print $2}'`
if [
.
.
.
done < email.sort
helyett
while read _SUM2 _PATH2;do
if [
.
.
.
done < email.sort
- A hozzászóláshoz be kell jelentkezni
micsoda egy láma vagyok :elpirulósszmájli:
köszi! :)
szerk.: csöppet gyorsabb lett...
- A hozzászóláshoz be kell jelentkezni
részemről az öröm ;)
- A hozzászóláshoz be kell jelentkezni
_COUNT=`expr $_COUNT + 1`
helyett
let ++_COUNT
- A hozzászóláshoz be kell jelentkezni
(( _COUNT= $_COUNT +1 ))
- A hozzászóláshoz be kell jelentkezni
kösz, ezt próbáltam én is, de ez csak bash-ban működik. (de végülis mindegy, átírtam az első sort és annyi.)
- A hozzászóláshoz be kell jelentkezni
Milyen egzotikus shellt használsz?
Itt eszi a ksh és sh is, és nem csak linuxon.
- A hozzászóláshoz be kell jelentkezni
tudom még fokozni:
a=$(( $a + 1 ))
De valódi Bourne-shell-ben csak az expr-es dolog jó egyedül :-(, mert a többi mind a ksh-ban bevezetett (onnan POSIX-sh-ba és bash-ba átkerülő forma)
- A hozzászóláshoz be kell jelentkezni
vagy tovább fokozva: $[ $a +1 ] :)
- A hozzászóláshoz be kell jelentkezni
ez ha lehet még roszabb, mert ez az igazi bashizm. Az enyim legalább egyéb posix-shellekben is megy.
- A hozzászóláshoz be kell jelentkezni
Az egész mehetne egy darab awk-ba, ennek add oda a sort kimenetét, és próbálgasd :)
awk 'BEGIN {md="x"}
$1==md { print "delete:", $0 ;}
$1!=md { print "egyedi", $0; md=$1}'
- A hozzászóláshoz be kell jelentkezni
áááá, ez is szép lenne, de az awk-t nem annyira szeretem :D és most a fentebbi megoldással sikerült megkerülni, az nekem úgy szimpi :) (és villámgyors is) inkább nem hoznám vissza az awk-t egy még bonyolultabb formában, amit még kevésbé értek :)
- A hozzászóláshoz be kell jelentkezni
Egy darab awk kiváltja a teljes while ciklust meg ami benne van: belerámolod a törlést system()-mel, némi kiírogatást, aztán kész. Ha nem érted, itt az ideje, hogy megismerkedj vele :-)
- A hozzászóláshoz be kell jelentkezni
ti miért szeretitek a fork bombát?
- A hozzászóláshoz be kell jelentkezni
Hol itt a forkbomb? Egy ciklus helyett egy darab jól megírt awk-script, ami ha kell, hív egy rm-et.
- A hozzászóláshoz be kell jelentkezni
nem mindegy, hogy awk-ban cikluson belül hívsz egy rm-et arra a fájlra, amiről kiderült, hogy duplikátum, vagy kiiratod az összes duplikátum fájl nevét az stdoutra, majd xargs rm-mel törlöd le.
- A hozzászóláshoz be kell jelentkezni
Ok. ez igaz - azt azért hozzáteszem, hogy az eredeti scriptben pont ugyanennyiszer hívja az rm-et (gyakorlatilag pont azt és úgy csinálja az awk, amit és ahogy a ciklus).
Az awk-ban a system() helyett { print $2 > "torolni" } és utána a torolni fájlt odaadni az xargs rm-nek. Meg persze az awk előtt illendően "> torolni" a bizronság kedvéért...
- A hozzászóláshoz be kell jelentkezni
az eredeti scriptben sem volt jól...
de minek raknád le fájlba???
/set mode kekec
mert powershellben úgy szokták?:PPPPPPPPPPP
- A hozzászóláshoz be kell jelentkezni
Nem, ott sem úgy szokták :-P Azon agyaltam, hogy a másik fájlt (ami megmarad, annak a listája) megy stdout-ra, holott annak kéne redirektálva a print :-P aztán beugrott, hogy fordítva kéne, de előbb postoltam...
- A hozzászóláshoz be kell jelentkezni
Ennyi lenne?
find . -name "*." -type f -exec md5sum -- {} + | sort | awk '{S1=$1; if(S1==S2) {gsub("^[[:xdigit:]]*[[:blank:]]*","");printf "%s\0",$0} else {S2=S1}}' | xargs -0 rm -f
- A hozzászóláshoz be kell jelentkezni
nem, mert a -name "*." nem jó, helyette '*.' kell.
ezenkívül még lehetne optimalizálni, én megtalálnám a módját, hogy egy md5sum-ot kelljen csak forkolni, illetve a gsub helyett is elég szerintem egy sima substr, mivel nem kell regexp, fix hosszú a hash mező.
- A hozzászóláshoz be kell jelentkezni
Igen "*." csere '*.' -ra jó meglátás, de a regexp annyiban jobb, hogy könnyebb továbbfejleszteni sha1sum-ra ;) Flexibilitás talán ennyit megér. Az md5sum annyiszor forkolódik csak amennyi paraméterrel egyszerre elbír, nem forkol minden file-ra kb mint az xargs.
Viszont nem esik kétségbe ha a file első karaktere - és attól sem ha szóköz vagy macskaköröm vagy aposztróf van a file nevében. (nem látható karakterekre pl backspace nem teszteltem :P)
Javított verzió:
find . -name '*.' -type f -exec md5sum -- {} + 2>/dev/null | sort | awk '{S1=$1; if(S1==S2) {gsub("^[[:xdigit:]]*[[:blank:]]*","");printf "%s\0",$0} else {S2=S1}}' | xargs -0 rm -f
- A hozzászóláshoz be kell jelentkezni
jó, nekem ez már nem olvasható :) ennyire nem kell az utolsó századmásodpercet is lefaragnom :) inkább legyen picit lassabb, de könnyen emészthető :)
viszont tényleg nem értem, miért kell a *. -ot bármiféle idézőjelbe tenni? (kivéve ha mondjuk " *." fájnévről lenne szó, de nem)
- A hozzászóláshoz be kell jelentkezni
Mert ha a futtató könyvtáradban vannak file-ok amikre teljesül a kifejezésed akkor azokat a shell szépen behelyettesíti neked a kifejezésed helyére és csak utána hívja meg a find-ot, de neked az nem lesz jó, meg a find-nak sem :) Ezért meg kell védened a kifejezésedet. Erre a legjobb az aposztróf de használhatnál visszafele perjelet (\) is így: \*.
Nem olyan bonyolult ez. Annyi baja azért van, hogy nem írja ki mennyi fájlt törölt, viszont amit letöröl azt gyorsan teszi. Ha az rm -f -et kicseréled ls -l -re akkor kipróbálhatod a sebességét.
Kicsit javítottam rajta:
find /mnt/data/cyrus -name '*.' -type f -exec md5sum -- {} + 2>/dev/null | sort | awk '{if($1==S) {gsub("^[[:xdigit:]]*[[:blank:]]*","");printf "%s\0",$0} else {S=$1}}' | xargs -0 rm -f
- A hozzászóláshoz be kell jelentkezni
szóval hiába adok meg find-nak egy abszolút elérési utat, a cwd-t is beleveszi? ezt nem is tudtam. ez bug vagy feature? :)
más: ha esetleg csak simán generálnék egy fájl listát, egy sima rekurzív "ls"-el vagy valahogy, majd fájlméret szerint rendezném, keresném a dupliktumokat méret alapján, és csak ott végeznék md5sum-ot, ahol az azonos fájlméret ezt indokolja? az azért többet érne a fenti optimalizácóknál, nem?
mert most mondjuk 1 percig md5sum meg, majd 5 másodperc az összes többi művelet (mostmár... az első verziómban ez 2-3 perc volt! :) ), amit ti igyekeztek még jobban lefaragni, de az már nem számít, hogy most az 5 másodperc vagy 4,8 vagy akár 1 másodperc... (szerk.: ja mert azt nem mondtam, hogy a duplikátumok aránya az eddig a legrosszabb esetben olyan 70db volt saccperkábé 2000 fájlból. tehát most 2000 fájlon megy md5sum, pedig elég lenne azt a 70-et megnézni)
na meg is próbálom ezt a második verziót megvalósítani.
----------------------------------
feel the beat - it's everywhere!
- A hozzászóláshoz be kell jelentkezni
Azt a "cwd"-t nem a find veszi bele, hanem még a find indulása előtt a shell dolgozza fel. A rekurzív ls-sel több baj is van, a legngyobb, hogy ott a listában nincs path, mert így néz ki a lista:
dir0:
név
név
név
dir1:
név
név
...
De tény, hogy az sokkal többet nyomna, ha le tudnád csökkenteni az md5 számolások darabszámát.
- A hozzászóláshoz be kell jelentkezni
kőbaltás módszer:
[code]
find $_PATH -type f -name '*.' -exec du -b {} \; > email.list
sort email.list -n -o email.sort
[/cpde]
csakhogy maga az algoritmus nem működik. legalábbis ebben a formában, ahogy az eredeti megoldás, úgy nem. :(
ugye azonos fájlméretű email az lehet rengeteg, 10-20 is akár, nyugodtan. ezek tartalma még nem biztos, hogy egyezik. azonban ha a fenti módon sorbarendezem, majd keresem a duplikátumokat ugyanúgy, mint eddig, akkor mondjuk az 1. találatot és a 2. találatot összehasonlítja md5 alapján, majd kiderül, hogy azok különbözőek, és ekkor ugrik tovább. emgnézi a 2. és 3. találatokat. azok is különböznek. ettől azonban még a 3. és az 1. lehet azonos. igazából itt kéne még egy lista az azonos fájlméreteket mindent megnélzni md5 alapjén is, majd ezt a listát sorba rendezni, és úgy válogatni ki az azonos md5 fájlokat. na de ez már bonyolult... :)
- A hozzászóláshoz be kell jelentkezni
Ha ugyanazt az elvet alkalmazod a fájl méretekre először amit az md5-ökre csináltunk akkor első körben kiszűröd az egyedi fájlmérettel rendelkezőket. Ezzel ezek md5 sumját megspórolod. Valahogy így:
find /mnt/data/cyrus -name '*.' -type f -exec stat -c "%s %n" {} + 2>/dev/null| sort -n | awk '{if ($1==S) {gsub("^[[:digit:]]*[[:blank:]]*","");printf "%s\0",$0} else {S=$1}}' | xargs -0 md5sum | sort | awk '{if($1==S) {gsub("^[[:xdigit:]]*[[:blank:]]*","");printf "%s\0",$0} else {S=$1}}' | xargs -0 rm -f
Ilyesmire gondoltál?
- A hozzászóláshoz be kell jelentkezni
ez a szkripted hash-e, vagy mi? :D
fogalmam sincs, hogy erre gondoltam-e, mert ez nekem így kínai :D lehet, hogy menő dolog egy sorba mindent összehányni, de én írtam az elején is, hogy nem értek hozzá, úgyhogy nekem ez olvashatatlan.
én így módosítottam próbaképp, de ez így nem jó (az elv sem).
viszont most már bőven elégedett vagyok az eredménnyel, úgyhogy nagyon nem akarom már tovább faragni a dolgot, innentől kevesebb időt nyerek vele 10 év alatt, mint amennyit most ráfordítaniék :) (persze tanulásnak nem rossz)
- A hozzászóláshoz be kell jelentkezni
Igazából nem is jó, most javítom :) Szkriptnek nagyon nem OK, de az elvet kipróbálni megfelelő egy ilyen egysoros is. Az elve az lenne, hogy azokat a fájlokat amelyeknek egyedi a mérete azonnal kivenné listából és csak olyan fájlokat vizsgálna tovább amelyekhez hasonló méretűek vannak a listában.
A javított verzió:
find /mnt/data/cyrus -name '*.' -type f -exec stat -c "%s %n" {} + 2>/dev/null| sort -n | awk 'BEGIN {L="";S=-1} {if($1==S) {gsub("^[[:digit:]]*[[:blank:]]*",""); printf "%s\0%s\0",L,$0;L=""} else {L=$0; gsub("^[[:digit:]]*[[:blank:]]*","",L)} ; S=$1;}' | xargs -0 md5sum | sort | awk '{if($1==S) {gsub("^[[:xdigit:]]*[[:blank:]]*","");printf "%s\0",$0} else {S=$1}}' | xargs -0 rm -f
Ha az rm -f -et ls -l -re cseréled és leméred az idejét akkor kb megtudod, hogy ez mennyit segítene a mintádon.
Olvashatóan ugyanez:
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin
umask 077
find /mnt/data/cyrus -name '*.' -type f -exec stat -c "%s %n" {} + 2>/dev/null | sort -n | awk '
BEGIN {
L=""
S=-1
}
{
if($1==S) {
gsub("^[[:digit:]]*[[:blank:]]*","")
printf "%s\0%s\0",L,$0
L=""
} else {
S=$1
gsub("^[[:digit:]]*[[:blank:]]*","")
L=$0
}
}' | xargs -0 md5sum | sort | awk '
{
if($1==S) {
gsub("^[[:xdigit:]]*[[:blank:]]*","")
printf "%s\0",$0
} else {
S=$1
}
}' | xargs -0 echo rm -f
- A hozzászóláshoz be kell jelentkezni
a find -exec tudtommal minden fájlra külön forkolja az md5sumot.
- A hozzászóláshoz be kell jelentkezni
A find man lapját időnként érdemes elolvasni :
-exec command {} +
This variant of the -exec action runs the specified command on the selected files,
but the command line is built by appending each selected file name at the end; the
total number of invocations of the command will be much less than the number of
matched files. The command line is built in much the same way that xargs builds its
command lines. Only one instance of ‘{}’ is allowed within the command. The command
is executed in the starting directory.
- A hozzászóláshoz be kell jelentkezni
ok, most látom, hogy {}+-t írtál. sorry.
- A hozzászóláshoz be kell jelentkezni
aki a uniq parancs helyett ekkora böszmeséget irogat, az megérdemli...
- A hozzászóláshoz be kell jelentkezni
beszarok hogy mindenre van kész parancs! :) sajnos ez nem jó a jelen helyzetre. :( pedig szép lett volna. :(
se a -d nem jó (mivel a path és fájlnevek lehetnek különbözőek sőt, tutira különbözőek), se a -f, se a -s (ennek a kettőnek pont az ellentéte kéne)
- A hozzászóláshoz be kell jelentkezni
a duplikátumok megkeresésére jó, közben rájöttem, hogy arra tényleg nem, hogy az elsőt meghagyd, a többit letöröld. de még agyalok egy kicsit, hogy ki lehet-e ezt trükközni.
- A hozzászóláshoz be kell jelentkezni
Emlékeimben az van, hogy az awk tud asszociatív tömböket kezelni.
Tehát csinálsz benne egy tömböt, amiben a tömbindex az md5, az értéke meg simán 0 vagy 1, és amelyik tömbindex már benne van, az ahhoz tartozó path-t kiíród a kimenetre.
fordított aposztrófról javasolt leszokni, mert nem egymásbaágyazható és deprecated. $() a helyes.
Ha az md5 sum kimenetét pipe-olod a sortba, akkor egy fájllal kevesebb.
- A hozzászóláshoz be kell jelentkezni
a fordított aposztrofot így szedtem ki inkább:
find /mnt/data/cyrus -type f -name *. -exec md5sum {} \; > email.list
mert az eredeti megoldás elhasalt a szóközös könyvtárakon (perszehogy a tesztgépen nem voltak szóközös könyvtárak...)
- A hozzászóláshoz be kell jelentkezni
a simát is kiszedted... kár volt érte.
- A hozzászóláshoz be kell jelentkezni
milyen simát? az nem is volt benne. vagy az idézőjelet érted a "*." körül?
- A hozzászóláshoz be kell jelentkezni
igazad van, idézőjel volt, nem sima. de oda kell a sima aposztróf.
- A hozzászóláshoz be kell jelentkezni
- A hozzászóláshoz be kell jelentkezni
mit szeretnél tulajdonképpen? hash alapján összehasonlított duplikátumokat találni rekurzívan? én erre ezt írtam:
find ! -type d -print0 | xargs -0 md5sum | sort | uniq -D -w 32
- A hozzászóláshoz be kell jelentkezni
hát itt ugye magából az md5sum-ból már relatív kevés példányt indítasz, kár hogy az viszont minden fájl hash-ét kiszámolja (tehát szerintem iszonyat lassú). Arról már nem is beszélve, hogy vajon mi a franc lehet ez a két uniq opció, mert én még az életben nem hallottam róluk (OK, uniq-ot azért nem használok naponta), de nem is szerepel a FreeBSD-s man-ban - azaz má megint valami gnuizm lehet.
- A hozzászóláshoz be kell jelentkezni
nem cél hogy minden fájlra kiszámoljuk a hash-t? mert ha más a neve a fájlnak, de a tartalma ugyanaz, akkor is duplikátumnak veszem.
amúgy igen, kicsit gnu-s ez :)
man-ból:
-D, --all-repeated[=delimit-method]
print all duplicate lines delimit-method={none(default),prepend,separate}
Delimiting is done with blank lines.
-w, --check-chars=N
compare no more than N characters in lines
- A hozzászóláshoz be kell jelentkezni
pont ez a lényeg, hogy mi módon lehetne gyorsítani. A név alapú azonosítás egyértelműen nem jó, de logikus, hogy ha pl. a méretük különbözik, akkor azokkal már nem kell semmit csinálni, míg azonos méret esetén (de csak akkor) jöhet az ellenőrzőösszeg.
- A hozzászóláshoz be kell jelentkezni
ja, az más. akkor így csinálnám:
find ! -type d | xargs du -b | sort -n \
| sed -r s/"\t"/"\t "/ \
| uniq -D -w 16 | sed -r s/"^[0-9]*\t* *"/""/ \
| xargs md5sum | sort | uniq -D -w 32
vagy \0 végződéssel:
find ! -type d -print0 | xargs -0 du -b | sort -n \
| sed s/"\t"/"\t "/ \
| uniq -D -w 16 | sed -r s/"^[0-9]*\t* *"/""/ \
| tr -s "\n" "\0" | xargs -0 md5sum | sort | uniq -D -w 32
...így csak az egyforma nagyságú fájlokra fut le a hash check.
- A hozzászóláshoz be kell jelentkezni
Mi lesz ha a file mérete nagyobb lesz mint 16 karakter?
Ha a du -b helyett stat -c "%s %n" -t használnál akkor az első sed feleslegessé is válna. Első xargs-ot pedig bele lehetne építeni a find-ba kb így:
Eredeti:
find ! -type d -print0 | xargs -0 du -b | sort -n | sed s/"\t"/"\t "/ |
Javaslatom:
find ! -type d -exec stat -c "%s %n" {} + | sort -n |
- A hozzászóláshoz be kell jelentkezni
"Mi lesz ha a file mérete nagyobb lesz mint 16 karakter?"
mi lesz? öröm s bódottá, hogy ekkora diszkem van amire ez ráfér! :D másrészt emailben nem annyira szokás ilyen n petabájtokat küldözgetni :D
- A hozzászóláshoz be kell jelentkezni
Nem kell ahhoz, nagy diszk.
# ls -l /var/tmp/cucc
-rw-r--r-- 1 root root 2195802030080 May 28 14:53 /var/tmp/cucc
# ls -lh /var/tmp/cucc
-rw-r--r-- 1 root root 2.0T May 28 14:53 /var/tmp/cucc
# df -hP .
Filesystem Size Used Avail Use% Mounted on
/dev/vg/lv 7.8G 150M 7.3G 2% /var/tmp
De így is csak 13 számjegy.
- A hozzászóláshoz be kell jelentkezni
"Mi lesz ha a file mérete nagyobb lesz mint 16 karakter?"
igen, ezt még be kell optimalizálni, sajna most ennyi időm volt rá, még elgondolkodok rajt.
- A hozzászóláshoz be kell jelentkezni