Kirjoittaja Aihe: Etsi-Korvaa monta tiedostoa ja monta sanaa samalla?  (Luettu 3453 kertaa)

odysseus

  • Vieras
Eli siis kyse on siitä, että onko jotain valmista palikkaa joka tekee seuraavaa:

-etsii ja korvaa sanan (tmv) useasta tiedostosta (kaikista hakemistossa ja alihakemistoissa)
-tekee saman usealle etsi-korvaa parille yhdellä kertaa

Tämä voisi siis olla ohjelma (mieluiten komentoriviltä), joka lukee parametrina "etsi-korvaa" tiedoston ja sitten käsittelee parametrina annetun hakemiston ja sen alihakemistot (kaikki tiedostot).
Luettava etsi-korvaa input-tiedosto voisi olla vaikka muotoa:

ETSI=KORVAA
ETSI2=KORVAA2
JUUPAJUU=JOOPAJOO
...

Tai ihan mitä tahnansa vastaavaa.

Onko siis tiedossa tuommoista suoraan olemassa tai helpolla scriptillä tehtävissä? Itse rupesin jo ajattelemaan kaikkea liikaakin ja mietin, että ehkä C-preprocessor ja makefile tekisi tuon #define:illä, mutta menee hankalaksi. Pitääkö tässä vääntää tuo itse ohjelmaksi?

kamara

  • Käyttäjä
  • Viestejä: 3031
    • Profiili
Vs: Etsi-Korvaa monta tiedostoa ja monta sanaa samalla?
« Vastaus #1 : 27.05.13 - klo:17.09 »
En jaksa ruveta vääntämään valmista ratkaisua, mutta awk:lla sellaisen tekeminen saattaisi olla melko yksinkertaista.

jekku

  • Käyttäjä
  • Viestejä: 2624
    • Profiili
Vs: Etsi-Korvaa monta tiedostoa ja monta sanaa samalla?
« Vastaus #2 : 27.05.13 - klo:18.03 »
Ainakin yksi juttu sinun on tarkennettava, tarkoitatko sanoja vai merkkijonoja.
Meinaan on eri juttu korvata lauseesta ETSI sanana kuin merkkijonona.
Jos on sana ETSIpä niin pitäisikö tuostakinkin korvata merkkijono ETSI?

Jos kyse vain merkkijonopareista niin käyttäisin sanaparitiedostossa välilyöntiä erottimena ja
sitten vaan
Koodia: [Valitse]
while read e k
do
sed s/$e/$k/g -i kohdefile
done < sanaparitiedosto
Voisi toimiakin ;)

Ja tällaiseen skriptiin olisin valmis tekemään vaikka funktion tuosta sedisilmukasta...

odysseus

  • Vieras
Vs: Etsi-Korvaa monta tiedostoa ja monta sanaa samalla?
« Vastaus #3 : 28.05.13 - klo:17.40 »
Ainakin yksi juttu sinun on tarkennettava, tarkoitatko sanoja vai merkkijonoja.
Meinaan on eri juttu korvata lauseesta ETSI sanana kuin merkkijonona.
Jos on sana ETSIpä niin pitäisikö tuostakinkin korvata merkkijono ETSI?

Jos kyse vain merkkijonopareista niin käyttäisin sanaparitiedostossa välilyöntiä erottimena ja
sitten vaan
Koodia: [Valitse]
while read e k
do
sed s/$e/$k/g -i kohdefile
done < sanaparitiedosto
Voisi toimiakin ;)

Ja tällaiseen skriptiin olisin valmis tekemään vaikka funktion tuosta sedisilmukasta...



Tässä on idistä.

Todellakin ongelmani on "tekninen", eli pitää korvata "TAGeja" jollain merkkijonolla.

Siis mallilla:

TAGI1=sana
TAGI2=sitä sun tätä
TAGI3=jotain muuta, mutta vain rivinvaihtoon saakka

Eli siis voin itse määrätä (input-tiedostossa) mitä etsitään ja millaiseksi korvataan.

Kyseessä on eräiden useissa hakemistoissa olevien konfiguraatiotiedostojen kustomointi, eli esimerkiksi jos  on vaikkapa 100 kpl asiakkaita, joilla "samanlainen systeemi", mutta "oma konffis", niin pitää muuttaa (useampaan) "tiedosto-templateen" esimerkiksi asiakkaan nimi, kotihakemisto ja vaikkapa IP osoite ja domain nimi jne. Tämä toimisi siis mallilla, jossa luetan tiedosto, jonka sisältö on:

{CUSTOMER_NAME}=Yritys Oy
{CUSTOMER_PHYSICAL_ROOT}=/var/www/yritys/
{CUSTOMER_PUBLIC_IP}=000.000.000.000
{CUSTOMER_PUBLIC_DOMAIN}=yritys.com

jne....

Edit: voisihan nuo tagien sisällöt tulla vaikka tietokannastakin...


Hakemistorakenne templateille voi olla vaikkapa:

yritys/
 |__etc
 |     |_tiedosto1.conf
 |     |_tiedosto2.conf
 |__var
      |_joku_hakemisto
           |_tiedostoX.YYY

Olisi siis tarkoitus saada generoitua nuo valmiiksi tuotantoonsiirtoa varten asiakaskohtaisesti.
« Viimeksi muokattu: 28.05.13 - klo:17.42 kirjoittanut odysseus »

jekku

  • Käyttäjä
  • Viestejä: 2624
    • Profiili
Vs: Etsi-Korvaa monta tiedostoa ja monta sanaa samalla?
« Vastaus #4 : 28.05.13 - klo:19.21 »
Jassoo, jaajoo...
Joten arvoparien ensimmäistä osaa ei tarvitse muuttaa, kunhan korjaa sen toisen osan?
Ja tarvittaessa lisää avaimen ellei sitä ole?

Mutta esimerkkisi mukaan tuo kenttäerotin on yhtäsuuruusmerkki ja sillä siisti.
Eli kääntyisin nöyränä poikana awk:n puoleen ja lukaisen muuttujat

Koodia: [Valitse]

while read raw
do
e=$(echo $raw |awk -F'=' '{print $1}')
k=$(echo $raw |awk -F'=' '{print $2}')
echo $e $k
done < parit.lst


odysseus

  • Vieras
OK, sori hieman pitkä viive vastaukselle, eli muita duuneja välissä... ;-)

Kun en nyt tunne kovin hyvin tuota awk:ta ja ei ollut aikaa pahemmin tuunata, niin päädyin sitten tähän "ei niin kauniiseen" ratkaisuun. Se toimii osaltani (vaikka onkin ohjelmointiteknisesti hieman typerä).

Koodia: [Valitse]
#!/bin/bash

DPATH="./testi/*"
TFILE="/tmp/frt.tmp.$$"

function _find_replace {
  while read raw
  do
    e=$(echo $raw | awk -F'=' '{print $1}')
    k=$(echo $raw | awk -F'=' '{print $2}')

    for f in $1
    do
      if [ -f $1 -a -r $1 ]; then
       sed "s/$e/$k/g" "$1" > $TFILE && mv $TFILE "$1"
      else
       echo "Error: Cannot read file $1"
      fi
    done
  done
}

function _read_file {
  for f in $1
  do
    if [ -d "$1" ]
    then
      for ff in $1/*
      do      
        _read_file $ff
      done
    else
      _find_replace $1
    fi
  done < parit.lst
}

_read_file $DPATH


Toisaalta alkuperäinen kysymyshän oikeastaan oli, että löytyykö valmiina, joten jos ei löydy, niin tässä on siis "puolivalmis". Joku voi ehkä tuunata tuohon tiedostontyyppien etsinnän jne... Nythän tuo korvaa annetusta polusta "kaikki filet" ja ne tagit jotka löytyvät tiedostosta "parit.lst".

Edit: tagasin ratkaistuksi.
« Viimeksi muokattu: 31.05.13 - klo:15.21 kirjoittanut odysseus »

jekku

  • Käyttäjä
  • Viestejä: 2624
    • Profiili
-----
Toisaalta alkuperäinen kysymyshän oikeastaan oli, että löytyykö valmiina, joten jos ei löydy, niin tässä on siis "puolivalmis". Joku voi ehkä tuunata tuohon tiedostontyyppien etsinnän jne... Nythän tuo korvaa annetusta polusta "kaikki filet" ja ne tagit jotka löytyvät tiedostosta "parit.lst".

Edit: tagasin ratkaistuksi.


Alkuverryttelynä voisi käyttää ihan tiedoston nimeen perustuvaa suodatusta.
Kuten jossain vilahti malli, niin tiedostot olivat nimetty tyyliin jotain.conf

Tekisin listan jotenkin vaikka:

Koodia: [Valitse]

echo $(find $alkuhakemisto -name "*conf")


Mutta kuten hyvin tiedät niin tapoja on monia - ja useimmat tekevät sen kun pyydetään :)

Tietysti jos haluaa pelata hiukan varmemman päälle niin ehdollistaa tiedostotyypin mukaan
Toistaiseksi on riittänyt ihan 'file'

Koodia: [Valitse]

~$ file /etc/dhcp/dhcpd.conf
/etc/dhcp/dhcpd.conf: ASCII English text



Beluga

  • Käyttäjä
  • Viestejä: 47
    • Profiili
Vs: Etsi-Korvaa monta tiedostoa ja monta sanaa samalla?
« Vastaus #7 : 31.05.13 - klo:19.49 »
Hei, mites tämä: http://docs.kde.org/stable/en/kdewebdev/kfilereplace/kfilereplace-the-add-dialog.html
Winkun puolella on tullut käytettyä .CSV-tiedostoja ymmärtäviä softia, kuten PowerGREP ja TextCrawler, joten aihe on tuttu.

petteriIII

  • Käyttäjä
  • Viestejä: 693
    • Profiili
Vs: Etsi-Korvaa monta tiedostoa ja monta sanaa samalla?
« Vastaus #8 : 01.06.13 - klo:15.31 »
Minulla tuli tarve muuttaa sana kaikkialla määrättävässä tiedostojärjestelmän osassa. Itse käsky on yksinkertainen: find mistä_kansiosta_eteenpäin_muutetaan -type f -exec sed -i "s/mikä/miksi/g" {} \;
- käsky toimi ihan oikein. Toivoin vain myöhemmin etten olisi käyttänyt sitä sillä se muutti järjestelmässäni kaiken minkä halusin ja paljon sellaista mitä en olisi halunnut.
- tajusin sentään ennen käskysuoritusta ottaa backupin joten tuhraantui vain aikaa.

# edellinen käsky muuttaa välittämättä siitä mitä vaihdettavan edessä ja perässä on. Seuraava kolmilauseinen käsky olettaa
 että muutettavan sanan edessä ja perässä on välilyönti. Tämä vastaa määritelmää: sana. Koska sana voi myös alkaa tai
lopettaa lauseen täytyy ennen muutoksia jokaisen rivin alkuun ja loppuun lisätä välilyönti ja muutoksien tekemisen jälkeen ne tulee poistaa.

find mistä -type f -exec sed -i 's/^ */\ /g;s/ *$/\ /g' {} \;    # tiedostojen rivien eteen ja perään lisätään välilyönti;
find mistä -type f -exec sed -i "s/\ mikä\ /\ miksi\ /g"  {} \; # sanojen muutokset tiedostoissa;
find mistä -type f -exec sed -i 's/^\ //g;s/\ $//g' {} \;         # tiedostojen rivien alusta ja lopusta poistetaan lisätty välilyönti

- siis etsittävän eteen ja perään ei yritetä liittää välilyöntiä; ne välilyönnit ovat muutettavassa tekstissä.
- tämä epämääräisyys on puhutun kielen ja kielioppien epämääräisyyttä ja koskevat millähyvänsä kielellä tehtyä ohjelmaa ja
 myös valmisohjelmia.
- edelliset kolme lausetta voi supistaa yhdeksi, mutta silloin selväpiirteisyys katoaa.

Mutta ei homma tähän lopu. Mahdollisuuksia on noin ziljoona. Pitäisi tehdä ohjelma jossa muutokset tehdään editorissa luvan
 jälkeen, se kelpaisi useimmiten.
Ja mikäli muutokset lukee tiedostosta tulee lisää epämääräisyyksiä elikkä automaatti-katastrofeja.
« Viimeksi muokattu: 01.06.13 - klo:21.23 kirjoittanut petteriIII »