Kirjoittaja Aihe: [Ratkaistu] viimeinkin: Tekstitiedostojen rakenteistaminen / soveltuva skripti  (Luettu 16877 kertaa)

JA5U

  • Käyttäjä
  • Viestejä: 463
    • Profiili
Jopas on taas bittimaailman ihmeitä.
Eilen seditin kaikki ; loppuiset rivit muotoon ;- ja tokihan silloin toimi.

Ja valitettavasti tiedosto sisältää tietoa, jota ei voi luovuttaa eteenpäin.
Eikä oikein pätkäkään auta tässä tapauksessa.
Muutoin olisin heittänyt sellaisen heti aloituksessa.

nm

  • Käyttäjä
  • Viestejä: 16430
    • Profiili
Jopas on taas bittimaailman ihmeitä.
Eilen seditin kaikki ; loppuiset rivit muotoon ;- ja tokihan silloin toimi.

En kyllä keksi, miten arvon puuttuminen voisi aiheuttaa ongelmia tuon skriptin kanssa. Siellä täytyy olla jotain muutakin erikoista rivinvaihtoihin liittyen.

Ja valitettavasti tiedosto sisältää tietoa, jota ei voi luovuttaa eteenpäin.
Eikä oikein pätkäkään auta tässä tapauksessa.
Muutoin olisin heittänyt sellaisen heti aloituksessa.

Yksi tapa löytää ongelmia aiheuttava kohta on leikata tiedostoa osiin puolittaen aina sen osan, jossa ongelma esiintyy. Lopulta pitäisi olla käsissä vain pieni pätkä, josta syyn voi löytää esimerkiksi heksaeditorin avulla. Silloin on myös mahdollista korvata arkaluontoiset merkkijonot geneerisillä nimillä esimerkkiä varten.

JA5U

  • Käyttäjä
  • Viestejä: 463
    • Profiili
Ei tää varmaan hirveästi auta, mutta CSV on siis seuraavanlainen:
Koodia: [Valitse]
rivi1_tunniste;rivi2_tunniste;rivi3_tunniste;...riviN_tunniste;
rivi1_arvo;rivi2_arvo;rivi3_arvo;rivi4_arvo
rivi4_arvo;rivi5_arvo...riviN_arvo;

Jaaaa, vaan nyt tuolla cat -v tarkasteltuna siellä onkin edelleen ^M merkkejä. Eli tuo ^M varmaan näyttäytyy tuollaisena "virheellisenä" CSVnä?

EDIT: yllättäen en enää muista, että kuinka sain osan niistä pois. SEDillä ei vaikuta luonnistuvan.
« Viimeksi muokattu: 11.05.16 - klo:21.59 kirjoittanut JA5U »

nm

  • Käyttäjä
  • Viestejä: 16430
    • Profiili
Jaaaa, vaan nyt tuolla cat -v tarkasteltuna siellä onkin edelleen ^M merkkejä. Eli tuo ^M varmaan näyttäytyy tuollaisena "virheellisenä" CSVnä?

^M = \r = CR eli Carriage Return. DOS- ja Windows-ohjelmat käyttävät CR+LF:ää (\r\n) rivinvaihtona, kun Unixissa käytetään pelkkää LF:ää.

tr on paras työkalu yksittäisten tai peräkkäin toistuvien merkkien muuntamiseen ja poistoon:

Koodia: [Valitse]
tr -d '\r' < input.txt > output.txt
Jos syötteessä on CR-merkkejä, rivien määrä riippuu tulkinnasta. Jotkut ohjelmat tulkitsevat ne rivinvaihdoiksi (esim. gedit tekee niin) ja jotkut näyttävät ^M-merkinnän tai jotain muuta.

JA5U

  • Käyttäjä
  • Viestejä: 463
    • Profiili
Mitenkäs tämä tr komento yhdistetään find jatkeeksi?

Koodia: [Valitse]
find  . -name "*.txt" -type f -exec tr -d '\r' < jotain > jotain #mutta miten

nm

  • Käyttäjä
  • Viestejä: 16430
    • Profiili
Mitenkäs tämä tr komento yhdistetään find jatkeeksi?

Koodia: [Valitse]
find  . -name "*.txt" -type f -exec tr -d '\r' < jotain > jotain #mutta miten

Esimerkiksi näin, jos haluat tehdä tiedostoille inplace-käsittelyn, eli kohdetiedosto on sama kuin lähde:

Koodia: [Valitse]
find  . -name "*.txt" -type f -exec sh -c 'cp {} "{}.tmp"; tr -d "\r" < "{}.tmp" > {}; rm "{}.tmp"' \;
Tai sedillä (mutta vain GNU-versioissa, ja muutenkin pienellä varauksella, koska eri sed-versiot saattavat käsitellä CR+LF-rivinvaihtoja eri tavoin):

Koodia: [Valitse]
find  . -name "*.txt" -type f -exec sed -i -e 's/\r//g' {} \;
« Viimeksi muokattu: 12.05.16 - klo:10.51 kirjoittanut nm »

JA5U

  • Käyttäjä
  • Viestejä: 463
    • Profiili
Mitenkäs tämä tr komento yhdistetään find jatkeeksi?

Koodia: [Valitse]
find  . -name "*.txt" -type f -exec tr -d '\r' < jotain > jotain #mutta miten

Esimerkiksi näin, jos haluat tehdä tiedostoille inplace-käsittelyn, eli kohdetiedosto on sama kuin lähde:

Koodia: [Valitse]
find  . -name "*.txt" -type f -exec sh -c 'cp {} "{}.tmp"; tr -d "\r" < "{}.tmp" > {}; rm "{}.tmp"' \;
Tai sedillä (mutta vain GNU-versioissa, ja muutenkin pienellä varauksella, koska eri sed-versiot saattavat käsitellä CR+LF-rivinvaihtoja eri tavoin):

Koodia: [Valitse]
find  . -name "*.txt" -type f -exec sed -i -e 's/\r//g' {} \;

Tämä oli muuten hyvä, mutta siinä kävi kuten epäilinkin eli nyt rivinvaihtoa tai välimerkkiä ei ole. Ilmeisesti tämä olisi ollut sitten sopivampi:
Koodia: [Valitse]
find  . -name "*.txt" -type f -exec sed -i -e 's/\r/\n/g' {} \;

AimoE

  • Käyttäjä
  • Viestejä: 2782
    • Profiili
Tämä oli muuten hyvä, mutta siinä kävi kuten epäilinkin eli nyt rivinvaihtoa tai välimerkkiä ei ole. Ilmeisesti tämä olisi ollut sitten sopivampi:
Koodia: [Valitse]
find  . -name "*.txt" -type f -exec sed -i -e 's/\r/\n/g' {} \;

Olen yrittänyt käsitellä Nordean verkkopankista haettua tapahtumaluetteloa noin, mutta ei toiminut. Tarkoitan kohtaa "sed 's/\r/\n/g'".

Ensinnäkin, se sed-versio joka tulee Ubuntun mukana ei tunnusta \r-merkkiä, kuten nm oikein varoitti. Toiseksi, sedillä ei saa kiinni rivinvaihtoa, koska sed käsittelee inputtia rivi riviltä niin että rivinvaihto ei ole mukana. Jos rivinvaihdon haluaa korvata jollain, sedille pitää erikseen kertoa että input halutaan lukea yhtenä rivinä, mikä on hirveän ruman näköistä.
 
Perlillä sen voi tehdä siististi:

Koodia: [Valitse]
perl -pe 's/\r\n//g' < input.txt > output.txt
mutta perl on liian järkäle näin pieneen juttuun.

Eipä yksittäisen tiedoston kanssa huomaa että cpua kuluu, mutta jos tiedostoja on paljon, niin sitten kannattaa nyplätä ja virkata sedin kanssa.

EDIT: Uups. Luin väärin kohdan  "sed 's/\r/\n/g'" koska olin juuri ollut käsittelemässä tätä Nordean tapahtumatiedoston tapausta. Tuo  "sed 's/\r/\n/g'" toimii jos sed tunnistaa \r:n. Mun tapauksessa siis oli tosiaan eri tilanne:  "sed 's/\r\n//g'".
« Viimeksi muokattu: 12.05.16 - klo:18.54 kirjoittanut AimoE »

nm

  • Käyttäjä
  • Viestejä: 16430
    • Profiili
Tämä oli muuten hyvä, mutta siinä kävi kuten epäilinkin eli nyt rivinvaihtoa tai välimerkkiä ei ole.

Kokeilitko tr:llä? Testaa ensin yksittäistä tiedostoa, jossa ongelma esiintyy. Ilman näytettä en oikein keksi, mikä noissa muunnoksissa voisi aiheuttaa ongelmia.

Voit myös tutkia rivinvaihtoja heksaeditorilla. \r on ASCII-merkki 13 eli heksadesimaalina 0d. LF-rivinvaihto \n on 10 eli 0a

JA5U

  • Käyttäjä
  • Viestejä: 463
    • Profiili
Olis pitäny hieman tarkentaa tilannetta.
Tarkoitin siis sitä, että siinä ^M tilalla tulisi olla se rivinvaihto.
Eli nyt sen ^M tilalle ei tullut mitään ja kaksi riviä ovat yhdessä.
Ts. rivi1;asd^Mrivi2;asd -> rivi1;asdrivi2;asd

Toinen kysymys eli miten tuolle datamash komennolle voisi syöttää tuon findin tuloksen?
Nyt se herjaa
Koodia: [Valitse]
#find . -name '*.txt' -type f -exec datamash -t';' {} \;
datamash: invalid operation './asd.txt'
Lyhyesti päättelin, että se johtuisi tuosta ./asd.txt eli sen pitäisi olla asd.txt.
Tod.näk. olen kuitenkin väärässä :)

nm

  • Käyttäjä
  • Viestejä: 16430
    • Profiili
Toinen kysymys eli miten tuolle datamash komennolle voisi syöttää tuon findin tuloksen?
Nyt se herjaa
Koodia: [Valitse]
#find . -name '*.txt' -type f -exec datamash -t';' {} \;
datamash: invalid operation './asd.txt'

Käyttöohjeen perusteella se lukee syötteen stdinistä ja käsitelty data annetaan ulos stdoutin kautta. Toimii siis kuten tr.

Koodia: [Valitse]
datamash -t';' transpose < input.txt > output.txt
Koodia: [Valitse]
find  . -name "*.txt" -type f -exec sh -c 'cp {} "{}.tmp"; datamash -t';' transpose < "{}.tmp" > {}; rm "{}.tmp"' \;

JA5U

  • Käyttäjä
  • Viestejä: 463
    • Profiili
No alkaahan tämä jo hiljalleen skulaamaan :)
Kaikkea oppii tai luulee oppivansa jatkuvasti - vielä, kun vaan muistaisi seuraavallakik kerralla, että miten se nyt olikaan.

Lopulta oikasin hieman:
Koodia: [Valitse]
find . -name '*.txt' -type f -exec bash -c 'txt2csv.sh "{}" > "{}".csv' \;
renamella muutin lopuksi txt.csv -> .csv, mutta joku hieno pikkujuttu varmaan mahdollistaisi suoraan csv päätteen.

Nyt pitäisi imasta nämä kantaan...
Toivottavasti kukaan ei tässä vaiheessa totea, että miksi nähdä näin paljon vaivaa, kun asian olisi voinut hoitaa jotenkin toisin  ;D
...mutta aikuisten oikeasti, jos on joku virtaviivaisempi keino, niin saa toki kertoa.

JA5U

  • Käyttäjä
  • Viestejä: 463
    • Profiili
No eipä tämä nyt suju.

Nuo ^M merkit kummitelevat edelleen ja tekevät mielenkiintoisia omituisuuksia PHP:ssä fgetcsvllä.

Ne pitäisi siis saada pois, mutta miten?

Ei auta:
Koodia: [Valitse]
find . -type f -name "*.txt" -exec vi {} -c ':silent!' -c ':%s/\^M/\r/G' -c ':wq' \;
Ei auta:
Koodia: [Valitse]
find . -type f -name "*.txt" -exec vi {} -c ':silent!' -c ':%s/<Ctrl-V><Ctrl-M>/\r/g' -c ':wq' \;

EDIT:
Merkillinen havainto, kun komennolla
Koodia: [Valitse]
cat tarkastelee tiedostoa, niin ^M sisältävän rivin alkuosa ei tulostu.
Kuitenkin
Koodia: [Valitse]
cat -v komennolla koko rivi tulostuu.
Rivi on siis muotoa: teksti^Mlisaatekstia (cat -v) tai lisaatekstia (cat)
« Viimeksi muokattu: 11.10.16 - klo:17.23 kirjoittanut JA5U »

nm

  • Käyttäjä
  • Viestejä: 16430
    • Profiili
Olisi helpompaa neuvoa, jos pystyisit antamaan pätkän ongelmatiedostosta esimerkkinä. Muuten menee täysin arvailuksi, miten nuo rivinvaihdot ovat seonneet.

jekku

  • Käyttäjä
  • Viestejä: 2624
    • Profiili
No eipä tämä nyt suju.

Nuo ^M merkit kummitelevat edelleen ja tekevät mielenkiintoisia omituisuuksia PHP:ssä fgetcsvllä.

Ne pitäisi siis saada pois, mutta miten?
.........


Oletkos moista kokeillut?
Koodia: [Valitse]
:~# aptitude search dos2unix
p   dos2unix       

JA5U

  • Käyttäjä
  • Viestejä: 463
    • Profiili
Kyllä, dos2unix on ollut kokeilussa, mutta sama lopputulos.  :-\

Eikös tuossa ylhäällä ole esimerkkirivi:
Rivi on siis muotoa: teksti^Mlisaatekstia (cat -v) tai lisaatekstia (cat)

cat -v
Koodia: [Valitse]
riviX;zxczxc
ongelmarivinalku;asd^Mjaloppu;wasd
riviY;xczxcz

cat
Koodia: [Valitse]
riviX;zxczxc
jaloppu;wasd
riviY;xczxcz
« Viimeksi muokattu: 11.10.16 - klo:18.12 kirjoittanut JA5U »

nm

  • Käyttäjä
  • Viestejä: 16430
    • Profiili
Eikös tuossa ylhäällä ole esimerkkirivi:
Rivi on siis muotoa: teksti^Mlisaatekstia (cat -v) tai lisaatekstia (cat)

Haluaisin nähdä palan alkuperäisestä tiedostosta ilman mahdollista editorin tai päätteen tekemää muunnosta, jotta voisin tutkia sitä binäärimuodossa heksaeditorilla. Muuten on vaikea arvata, mitä tiedosto oikeasti sisältää.

hexdumpin listaus kelpaa myös:

Koodia: [Valitse]
hexdump -C tiedosto.txt

JA5U

  • Käyttäjä
  • Viestejä: 463
    • Profiili
Muokkasin itselleni tällaisen, joka ratkaisi asian, mutta aiheutti tyypillisen "nokka irtoaa, niin pyrstö tarttuu" eli menetin ääkköset:

Koodia: [Valitse]
#make a backup
cp $1 $1.orig

#Tekee jonku muutoksen ä->a tmv.
iconv -t ascii//TRANSLIT $1.orig > $1.temp

#Strip out other unprintable characters  -whatevs
strings $1.temp > $1

#Remove temp file.
rm $1.temp

Ja jos käytän tiedoston Sublimen kautta, niin ongelmat ts.merkit katoavat eikä dataa menetetä.
Joten teen siis komennon joka pyöräyttää tiedostot taustalla Sublimen kautta.

Tässä kuitenkin vielä UUSI hexdump ongelmakohdasta:
Koodia: [Valitse]
00000000  65 72 65 68 64 79 73 3b  0a 65 74 75 6e 69 6d 69  |erehdys;.etunimi|
00000010  3b 74 65 72 6f 0a 73 75  6b 75 6e 69 6d 69 3b 61  |;tero.sukunimi;a|
00000020  6e 74 65 72 6f 0a 6c 61  68 69 6f 73 6f 69 74 65  |ntero.lahiosoite|
00000030  3b 6b 6f 74 69 6b 61 74  75 20 38                 |;kotikatu 8|
0000003b

« Viimeksi muokattu: 11.10.16 - klo:19.54 kirjoittanut JA5U »

nm

  • Käyttäjä
  • Viestejä: 16430
    • Profiili
Jees, ongelma näkyi siinä dumpissa jonka ehdit poistaa, eli tiedostossa oli enimmäkseen LF-rivinvaihdoilla erotettuja rivejä, mutta yksi CR (0x0d) kohdassa, jossa kuuluisi olla rivinvaihto. Jokin on siis pudottanut siitä kohdasta LF:n (0x0a) pois tai korvannut sen CR:llä.

Varmin ratkaisu olisi käyttää ensin dos2unix-komentoa (tai vastaavaa sed-skriptiä) siltä varalta, että vastaan tulee CR+LF-rivinvaihtoja, mutta jatkaa sitten muuntamalla yksinäiset CR-rivinvaihdot LF-rivinvaihdoiksi. Eli jotakuinkin tähän tapaan:

Koodia: [Valitse]
dos2unix -n tiedosto.txt temp.txt
Koodia: [Valitse]
tr '\r' '\n' < temp.txt > korjattutiedosto.txt

Tämä toimii siis olettaen, että CR-merkkejä on vain sellaisissa kohdissa, joissa kuuluu olla rivinvaihto. Jos niitä on myös muualla, olet syvässä suossa.
« Viimeksi muokattu: 11.10.16 - klo:20.47 kirjoittanut nm »

JA5U

  • Käyttäjä
  • Viestejä: 463
    • Profiili
Tämä toimii siis olettaen, että CR-merkkejä on vain sellaisissa kohdissa, joissa kuuluu olla rivinvaihto. Jos niitä on myös muualla, olet syvässä suossa.

Eli kuten tuossa esimerkkirivillä on keskellä riviä ^M, niin olen suossa?

Mutta jos saan tuon sublimen toimimaan, niin en kenties olekaan...

EDIT:
No eihän se Sublimessä pyöräyttäminen muuttanut mitään, kun se tehtiin komentorivin kautta.
Jos avaa käyttöliittymässä, niin silloin kyllä tiedostot korjaantuvat pelkällä 'save' toiminnolla.

HUOH...
« Viimeksi muokattu: 11.10.16 - klo:22.45 kirjoittanut JA5U »