két fájl különbsége

Sziasztok!

Van két fájlom ilyen formában:

3213 1 lrwxrwxrwx 1 root root 21 Sep 7 21:19 /platform/SUNW,Netra-T12/kadb -> ../SUNW,Sun-Fire/kadb

Ehhez és hasonló sorokkal van tele. Pár ezer sor. Az egyik egy patch -elés előtti, a másik a patch -elés utáni fájlrendszer állapot. A két fájlban a sorok száma eltérő. Ki kellene "vonnom" az első fájlból a második sor tartalmát, úgy hogy sorok szerinti egyezések alapján hasonlítsam össze a két fájlt.
Gondoltam awk -ra, de nem használtam korábban. Tudnátok egy picit segíteni? Előre is köszike!

Hozzászólások

Ha egy picit is ismered a vi-t, akkor a vimdiff nagy segítséged lesz ebben a problémában.

Csináltam hasonlót. De nem awk-val, hanem sima while read és ifekkel. Kicsit gány ugyan, de működik. Hátránya, hogy az egyik fájlt annyiszor olvassa be, ahány sora van a másik fájlnak.

"A"-ból olvas majd "B"-ből az összes sort, amig nem talál azonost. Ha azonost talál továbbmegy "A" következő sorára, ha nem talál, akkor kiírja.

Mondom. gány - de szódával elmegy.

comm parancs tökéletes ilyesmire.

KisKresz

sort + diff, ez a legegyszerűbb út.
Esetleg még ez:


cat file1 file2| awk '{print $11 $12 $13}' | sort | uniq 

Ha minden igaz, akkor egy listát készít a fájlokról, amik újonnan jöttek létre
Ha a file megmaradt csak időpont változást keresel, akkor az awk-s részt vedd ki. Igaz, hogy a módosult fájlok kétszer lesznek meg, de azt már scripttel könnyen ki lehet venni, és mégiscsak kissebb anyag. + lehet grep-pel szórakozni, hogy a /etc vagy ilyesmi nem érdekel.

Alakul a dolog. Viszont most ki kellene cserélnem a ./utvonal/fajlnev formátumú részeket a txt fájlokban /utvonal/fajlnev formatumra. Így próbáltam:


#cat old.txt | sed 's/\.//\//g' > old2.txt

Erre ezt kaptam:


sed: -e kifejezés #1, karakter 7: unknown option to `s'

Ebben tudnátok segíteni?

--
Lógnak a pálmafán a kókuszok .... :)
http://laszlo.co.hu/

Sajnos még így is adódik probléma. Nem csak ott cserélgeti le a dolgokat, ahol szeretném.
Szóval így fest egy sor:


lrwxrwxrwx ./usr/proc/bin/pldd -> ../../bin/p

Én ebből szeretnék:


lrwxrwxrwx /usr/proc/bin/pldd -> ../../bin/p

formátumút csinálni, de a feljebb írt sed nem csak a második szóban cserélgette ki a ./ -t

--
Lógnak a pálmafán a kókuszok .... :)
http://laszlo.co.hu/

irj hosszabb regexpet, ami csak azt fedi le, ami neked kell. A sed nem tudom pontosan hogyan kezeli a regexpeket, de perles regexppel valami ilyen kene:

/^(.+ )\.(/.+ -> .+)$/$1$2/

persze ha nem minden file link, es nincs mindegyik sorban szep nyil, akkor nehezebb az ugy, de akkor is az a lenyeg, hogy olyan regexpet irj, ami csak azt fedi le, ami neked kell, es semmi mast. Amit te hasznalsz, az tul altalanos.

sed számomra undorító. Én szkriptekben a

j=${j//-xvid/""}

formát használom. Itt éppen a "-xvid"- et cseréli ki ... semmire. A

j=${j//"./"/""}

elvileg minden ./ -t cserél ki semmire azaz törli a ./-eket a j változóban. A többi meg gyerekjáték. Csak beolvasod readdel a fájl sorait, a fentiek szerint átalakítod és kiírod.

Azért, mert a "g" azt mondja, hogy a sorban az összes illeszkedő mintát cserélje le. Ha elhagyod a "g"-t, akkor csak az első előfordulásra hajtja végre a parancsot:

 echo "lrwxrwxrwx ./usr/proc/bin/pldd -> ../../bin/p" | sed 's/\.//'

bár én jobban szeretem a / helyet a ,-t használni, mert így szerintem olvashatóbb:

echo "lrwxrwxrwx ./usr/proc/bin/pldd -> ../../bin/p" | sed 's,\.,,'

Tehát ez csak annyit tesz, hogy minden sorban az első .-ot törli és kész.

s /szabályos kifejezés/helyettesítés/zászlók

A szabályos kifejezés előfordulásait helyettesíti az aktuális
szövegpufferben. A `/' kivételével minden karakter használható.
Teljesebb leírást lásd az ed (1) kézikönyv lapján. A zászlók a
következők lehetnek: (Bármelyikük előfordulhat, de az is lehet,
hogy egyikük sem.)

g -- Globális. A string minden nem átfedő megjelenését
helyettesíti. Ha nincs megadva, csak az első megjelenés
helyettesítődik.

p -- Kinyomtatja (print) a minta területet ha helyettesítés
történt.

w -- Írás (write). Az aktuális szövegpuffert egy argumentumként
megadott fájlhoz fűzi hozzá, ahogy a `w' parancsban, ha
helyettesítés történik. Ha nincs fájl argumentum, a szabványos
kimenetre történik az írás.

Bye, Fifi

Most olvasom, hogy mit is kell csinálni :) , bár nem igazán értem :(


fifi@blackdragon:~$ cat a.txt 
5
4
3
2
1
fifi@blackdragon:~$ cat b.txt 
1
3
5
7
9
2
4
6
8

A két file metszete kell, ami mindkét file-ban van?
Arra ez jó:

fifi@blackdragon:~$ cat a.txt b.txt | sort | uniq -d
1
2
3
4
5

Vagy az kell, hogy az egyik file melyik sorokkal több?
Arra meg ez:

fifi@blackdragon:~$ cat a.txt b.txt | sort | uniq -u
6
7
8
9

Szerintem a második változatot keresed, így újraolvasva ..

Bye, Fifi

Jó ez a sort és uniq páros. A sed arra kellett, hogy kicseréljek a sorokban bejegyzéseket, mert a két fájlista nem egyforma módszerrel készült.
Nagy részüket már kiszedtem, már sok nem maradt. Azzal majd holnap bírkózok tovább.
Köszönöm mindenkinek a segítséget!
(ám lehet, hogy holnap is kérek majd segítséget)

--
Lógnak a pálmafán a kókuszok .... :)
http://laszlo.co.hu/


$ bash
[zgabor@Lappantyu ~]$ a=1234
[zgabor@Lappantyu ~]$ echo ${a:1}
234
[zgabor@Lappantyu ~]$ echo ${a#?} 
234
[zgabor@Lappantyu ~]$ exit
$ ksh
$ a=1234
$ echo ${a#?}
234
$ 

Azaz javasolt a masodik forma, leven azt bash *is* es ksh *is* megeszi - ellentetben a :1-jellegu bash-izm-mel.

Alakul a scriptecske. Viszont a performanciájával nem vagyok megelégedve.
Egy SUN Fire V240 -esen futtatom, és a sorok száma az elemezendő fájlban ~140 ezer.
Íme a script:



#!/usr/bin/bash
processLine(){
  line="$@" # get all args
  F3=$(echo $line | awk '{ print $3}')
  F11=$(echo $line | awk '{ print $11}')
  F12=$(echo $line | awk '{ print $12}')
  F13=$(echo $line | awk '{ print $13}')


#megvizsgaljuk, hogy az adott sor milyen tipus, es csak a fajlokkal es linkekkel foglalkozunk
#ezt a harmadik fieldbol tudjuk eldonteni. ha fajl, akkor - ha link akkor l az elso karakter

if [[ ${F3:0:1} == "-" ]] || [[ ${F3:0:1} == "l" ]];
then
        if [[ ${F11:0:1} == "." ]];
        #Itt vizsgaljuk, hogy a sorok fajlnevei ./ -el kezdodnek -e vagy nem.
        #Ha ./ -el kezdodnek, akkor a pontot, azaz az elso karaktert levagjuk
        then
                #echo "Csere volt"
                F11=${F11:1}
                echo "$F3 $F11 $F12 $F13" >> old.txt
        else
                #echo "Nem volt csere"
                #F11=${F11:1}
                echo "$F3 $F11 $F12 $F13" >> new.txt
        fi
else
        #echo "Nem egyezik"
        continue
fi

}

FILE=""

if [ "$1" == "" ]; then
   FILE="/dev/stdin"
else
   FILE="$1"

   if [ ! -f $FILE ]; then
        echo "$FILE : does not exists"
        exit 1
   elif [ ! -r $FILE ]; then
        echo "$FILE: can not read"
        exit 2
   fi
fi

exec 3<&0
exec 0<$FILE
while read line
do
        # use $line variable to process line in processLine() function
        processLine $line
done
exec 0<&3

exit 0


Láttok benne valami javítani valót, amivel fokozhatnám a feldolgozás sebességét?
--
Lógnak a pálmafán a kókuszok .... :)
http://laszlo.co.hu/

Most csak így futtában, mintha az elején az echo parancsok feleslegesek lennének... illetve a szerkezet pazarló. Ha soronként négyszer meghívod az echo-t ráadásul awk-val az szerintem nagyon lelassít. Inkább "belső" szkriptutasításokat kéne használni.

  line="$@" # get all args
  F3=$(echo $line | awk '{ print $3}')
  F11=$(echo $line | awk '{ print $11}')
  F12=$(echo $line | awk '{ print $12}')
  F13=$(echo $line | awk '{ print $13}')

Nem nagyon latom,hogy miert is nem jo:
F3="${3}"
F11="${11}"
F12="${12}"
F13="${13}"
konstrukciok. line-ba beteszed az osszes parametert, csak azert, hogy utana kiszedjed ezt a negyet. bash/ksh tudja a "${xxxx}" pozicionalis parametert a 9. utan is (eredeti Bourne-shell nem tudja, de csak van azon a sunyin ksh is ;-), hamar bash van.)

Vagy esetleg maradhat, ha relatíve kevés a cserélendő sorok száma, de az F3 vizsgálatát, akkor vedd előbbre.
Tehát először adj értéket F3-nak, vizsgáld meg, hogy érdemes-e foglalkozni a sorral és ha érdemes, akkor adj értéket a többi háromnak.

Egy próbát megér, és ha így is lassú csak akkor kéne az átalakításon filózni.

Most már azon a részen dolgozok, ami összehasonlítja a két külön fájlba leválogatott, megszűrt sorokat.
Itt figyelembe vettem a tippedet, és valóban gyorsabban megy a dolog, bár így is jó sokáif el fog tartani. Köszi!
--
Lógnak a pálmafán a kókuszok .... :)
http://laszlo.co.hu/


exec 3<&0
exec 0<$FILE
while read line
do
        # use $line variable to process line in processLine() function
        processLine $line
done
exec 0<&3

Mi a francnak szorakozol a standard input ilyeten modon torteno megjegyzesevel/atiranyitasaval? (OK, ez a teljesitmenyen nem nagyon fog javitani, de kisse atlathatobb. Mi a rossz abban, hogy:


while read line
do
        # use $line variable to process line in processLine() function
        processLine $line
done < "$FILE"

A "
line="$@" # get all args
F3=$(echo $line | awk '{ print $3}')
F11=$(echo $line | awk '{ print $11}')
F12=$(echo $line | awk '{ print $12}')
F13=$(echo $line | awk '{ print $13}')
"

borzadály helyett pl set $(echo $@), majd az F3 helyett $3, F11 helyett $11, F12 helyett $12, satöbbi. De egyszerűen elég lehet szimplán csak a $i-re hivatkozni...

> borzadály helyett pl set $(echo $@)

Kollega, ez csak egy sokkal rejtettebb borzadaly, de ugyanolyan ronda.

0) nem hagyjuk le a valtozohivatkozas korul az idezojelet!

1) set -- blabla
Kell a --, ugyanis senki nem akadalyozza meg, hogy az atadott parameterekbol az elso "-" karakterrel kezdodjon, emiatt a "--" nelkul a shell azt a sajat opciojakent (felre)ertene

2) vegyuk eszre, hogy "$@" mar eleve tartalmazza az atadott parametereket, kovetkezeskent a set $( echo "$@" ) segitsegevel a parameterekbol parametereket csinaltunk. De legalabb meg egy parancshelyettesitest is beletettunk, hatha a process krealas dob a sebessegen. Khmm. Ennel azert hatekonyabban is lehet lassitani (es olvashatatlanna tenni) egy kodot.

3) $3 jo, de a $11 mar nem, mint fentebb irtam, ${11} az a forma, ahogyan azt POSIX-shell, ksh, neadjisten Bash alatt hasznalhato
(Solarison tesztelve). $11 = "$1"1 - azaz nem a 11. parameter, hanem az elso parameter erteke, moge ragasztva egy "1" sztring.

Ok. igazad van. A 0.-val pláne, meg a3.-mal is. A set $(echo...) utánn rögtön javítottam, mivel tényleg semmi értelme a $@-ot így szétszedni egy plusz processzel, bár az eredetiben egy rakat awk indult. A 3. javítást köszönöm, az tényleg el..ás a részemről.

Kicsit off:

Na itt vannak tök jó ötletek, kíváncsi vagyok, hátha másnak van kész megoldása a következő feladatra:

Készítettem biztonsági mentést cp-vel egyik vinyóról másikra. Szeretném tudni, hogy a másolt megegyezik-e az eredetivel. (Mert szívtam már meg ilyesmit).

Szóval arra gondoltam, hogy hash-t lenne jó összehasonlítani. Most épp odáig jutottam, hogy mindkét könyvtárszerkezetben futtattam kb. ezt:
find ebben abban -type f -exec md5sum {} \; >md5s

Tehát van két fájlom, ami md5sum-mal kezdődik, aztán relatív path és filenév. Gondoltam legyen sort, és hasonlítsuk össze! A gond az, hogy a path mindenhol eltér, tehát a diff, comm, ilyesmi rögtön különbségnek venné.

Szóval a kérdésem az, hogy hogy lehetne jól összevetni akár a két md5s fájlt, akár valami más módon a könyvtárakat.
Gondoltam arra, hogy kivágom az első oszlopot (az md5sumot), sort, uniq, és megnézem, hogy ugyanannyi sor van-e, mint korábban. Ha igen, akkor nincs azonos md5-tel fájl, és akkor elég diff-fel, comm-mal csak az md5-öket nézni. De ha ütközés van, vagy mondjuk azonos tartalmú fájl van több a fájlrendszerben, vagy ugyanaz a fájl többször, akkor ez nem jó.

G

van ugye két fájlod, amiben "MD5SUM /path1/file" illetve "MD5SUM /path2/file" sorok szerepelnek. Én az egyik, célszerűen a mentésről készült md5sum listában cserélném le a path2-t path1-re, aztán jöhet a diff, azaz sed 's/path2/path1/' mentes_md5sum.lst > mentes2.lst; diff -u eredeti.lst mentes2.lst

Esetleg rsync-es trükközés, van neki egy -n kapcsolója (dry-run)... Aztán lehet, hogy rákapsz arra, hogy rsync-kel backupolj majd a jövőben ("-n" nélkül...)