Nahrazení řetězce pomocí reg. výrazu

webhope

Nahrazení řetězce pomocí reg. výrazu
« kdy: 19. 03. 2010, 09:19:24 »
Snažím se vytvořit předlohu regularniho vyrazu ke skriptu na editaci souboru /etc/fstab . Předloha má hledat vybraný řádek. Znám hodnoty, které chci do té předlohy dosadit. Získávám je pomocí awk a slučuju do promenne pattern. Akorad tam potřebuju přidat znak whitespace, tedy neco jako \W+ . Mám tento kod:

Kód: [Vybrat]
uuid_=`echo $line | awk  '{print $1,"\W"}'` # stara hodnota - dostat promennou z awk do bashe
dir_=`echo $line | awk  '{print $2,"\W"}'` # stara hodnota - dostat promennou z awk do bashe
fs_=`echo $line | awk  '{print $3,"\W"}'` # stara hodnota - dostat promennou z awk do bashe
zbytek_=`echo $line | awk  '{print $4,"\W"$5,"\W"$6}'` # stara hodnota - dostat promennou z awk do bashe
pattern="$uuid_$dir_$fs_$zbytek_"; echo $pattern; read

Vraci to chybove hlasky: "awk: warning: escape sequence `\W' treated as plain `W'"
Poradite jak to osetrit? Díky

Edit: Sice bych to mohl dát rovnou do toho pattern, ale u promenne zbytek_ potrebuju vrazit to \W* mezi tri sloupce
« Poslední změna: 20. 03. 2010, 08:44:20 od webhope webhope »


deadmail

Re: Vytvoření předlohy reg. výrazu pomocí awk
« Odpověď #1 kdy: 19. 03. 2010, 16:27:37 »
Vobec nie je jasne co presne tam chcete urobit.

V regularnych vyrazoch pouzivany znak \W ma vyznam pri hladani nejakeho textu, ale nie vo vypise (print v awk).

Ciarka v akcii print v prikaze awk vypise oddelovac.

Kod v prispevku vyzera, ze len meni oddelovac na podciarkovnik (underscore) ...

Zmena (len vypis zmeneneho suboru) adresara v jednom riadku (podla povodnej hodnoty) by sa dala cez awk riesit napr. nejako takto:

Kód: [Vybrat]
line=$(tail -1 /etc/fstab) #povodny riadok (posledny z fstab)
dir="adr" #nova hodnota adresara
awk --assign=riadok="$line" --assign=hodnota="$dir" '{if ($0 == riadok) {$2=hodnota};print}' /etc/fstab

webhope

Re: Vytvoření předlohy reg. výrazu pomocí awk
« Odpověď #2 kdy: 19. 03. 2010, 17:48:01 »
Teď nevím co ten Váš kód udělá, to zapisuje rovnou do fstab?

Chtěl jsem jen toto - vytvorit predlohu jako "uuid=asdasdasd\W*/media/pokus\W*NTFS-3G\W*defaults,umask=000\W*0\W*"
Potřeboval bych jen lehce upravit ten můj kód, te zkouším změnu, stejně bez výsledku - stejný chyba. Chci do výstupu k $1 přidat zpětné lomítko a W*. Tedy aby se u každé proměnné nastavilo neco jako "text\W*"

Kód: [Vybrat]
id_=`echo $line | awk  '{print "$1 \W"}'` # stara hodnota - dostat promennou z awk do bashe
dir_=`echo $line | awk  '{print "$2 \W"}'` # stara hodnota - dostat promennou z awk do bashe
fs_=`echo $line | awk  '{print "$3 \W"}'` # stara hodnota - dostat promennou z awk do bashe
zbytek_=`echo $line | awk  '{print $4,"\W"$5,"\W"$6}'` # stara hodnota - dostat promennou z awk do bashe
pattern="$id_$dir_$fs_$zbytek_"; echo $pattern; read

edit:
co za jazyk pouziva ten awk, z ceho vychazi? je to perl?
« Poslední změna: 19. 03. 2010, 18:10:40 od webhope webhope »

deadmail

Re: Vytvoření předlohy reg. výrazu pomocí awk
« Odpověď #3 kdy: 19. 03. 2010, 20:35:51 »
ziadnu zmenu v subore fstab nerobi, len vypisuje na obrazovku. Bez obav mozete vyskusat ten kod, nic nemeni.

Ak chcete vypisat lomitko, tak ho musite "escapovat" = napisat dvakrat \\.

Kód: [Vybrat]
echo "Ahoj svet" | awk '{print $1"\\"$2}'

webhope

Re: Vytvoření předlohy reg. výrazu pomocí awk
« Odpověď #4 kdy: 20. 03. 2010, 08:22:51 »
Tak awk sice funguje:

Kód: [Vybrat]
echo "Tak toto je muj prvni pokus s awk" | awk  '{print $4"\\W"$5"\\W"$6}'

ale ja potrebuju ten vystup z awk ulozit do promenne. Delam to pomocit zpetnych uvozovek a proto to hlasi chybu:

Kód: [Vybrat]
id_=`echo $line | awk  '{print $1"\\"}'`
Čili ty zpetna lomitka se to snazi interpretovat jako wildcard

Edit:
Takže už to mám. Já vlastně na výstup musím dostat dvě zpětné lomítka, ne jedno:

Kód: [Vybrat]
id_=`echo $line | awk  '{print $1"\\\\W*"}'` # stara hodnota - dostat promennou z awk do bashe
dir_=`echo $line | awk  '{print $2"\\\\W*"}'` # stara hodnota - dostat promennou z awk do bashe
fs_=`echo $line | awk  '{print $3"\\\\W*"}'` # stara hodnota - dostat promennou z awk do bashe
zbytek_=`echo $line | awk  '{print $4"\\\\W*"$5"\\\\W*"$6}'` # stara hodnota - dostat promennou z awk do bashe
pattern="$id_$dir_$fs_$zbytek_"; echo $pattern; read

UUID=2090ACC103B52D41\W*/media/win_c\W*ntfs-3g\W*defaults,umask=000\W*0\W*0

Tak teď to jdu vyzkoušet, jestli mi bude fungovat ta předloha pro nahrazování. Zatim nefunguje.

Kód: [Vybrat]
replaced=${line//pattern/"tak toto je prepsana radka"};
« Poslední změna: 20. 03. 2010, 08:34:02 od webhope webhope »


webhope

Re: Vytvoření předlohy reg. výrazu pomocí awk
« Odpověď #5 kdy: 20. 03. 2010, 08:43:00 »
Tak ještě řeším toto:
1) nefunguje mi to nahrazení pomocí regulárního výrazu
2) ta proměnná $replaced je přístupná pouze uvnitř cyklu while ... do ... done; Ale za tím cyklem už přístupná není. Tohle neumím vyřešit...

Kód: [Vybrat]
# EDITACE SOUBORU /etc/fstab
n=0;echo "Vyber radek k editaci:"; read number; clear; echo -e "Vybral si radek:";
number=$number; # pokud to neulozim tak se promenna pri dalsim read vymaze
grep $e /etc/fstab | while read line; do
    let "n += 1";
    if [ "$n" == "$number" ]; then  # POCET OD NULY
      echo "$line" | awk '{print $1," \033[1;32m",$2,"\033[1;36m", $3, "\033[1;0m", $4, $5}';
      #awk -v w="$line" '{print w}'# dostat promennou do awk
      id_=`echo $line | awk  '{print $1"\\\\W*"}'` # stara hodnota - dostat promennou z awk do bashe
      dir_=`echo $line | awk  '{print $2"\\\\W*"}'` # stara hodnota - dostat promennou z awk do bashe
      fs_=`echo $line | awk  '{print $3"\\\\W*"}'` # stara hodnota - dostat promennou z awk do bashe
      zbytek_=`echo $line | awk  '{print $4"\\\\W*"$5"\\\\W*"$6}'` # stara hodnota - dostat promennou z awk do bashe
      pattern="$id_$dir_$fs_$zbytek_"; echo $pattern; read
      if [ "$dir_" == "/" ]; then escape=1; echo "Bod / pro pripojeni systemoveho oddilu neni povoleno nastavit."; fi;
      if [ "$dir_" == "/home" ]; then escape=1; echo "Bod /home neni povoleno nastavit."; fi;
      if [ "$dir_" == "swap" ]; then escape=1; echo "Oddil swap neni povoleno nastavit."; fi;
      replaced=${line//pattern/"tak toto je prepsana radka"};
echo $replaced"\n";
echo $pattern; read
    fi;
done
echo $replaced"\n";
echo $pattern; read
if [ "$escape" != "1" ]; then # pokud vybral / nebo /home, neaplikovat

Možná to dělám moc složitě, ale i tak bych to chtěl vyřešit. Když tak bych pak zkusil udelat to pomocí selectu, tím by odpadl problém s tou proměnnou mimo cyklus.
« Poslední změna: 20. 03. 2010, 08:46:12 od webhope webhope »

deadmail

Re: Nahrazení řetězce pomocí reg. výrazu
« Odpověď #6 kdy: 20. 03. 2010, 16:06:00 »
Citace
Možná to dělám moc složitě, ale i tak bych to chtěl vyřešit. Když tak bych pak zkusil udelat to pomocí selectu ...

Riesenie cez select (bez farieb):

Kód: [Vybrat]
#!/bin/bash
set +x
hledat=("NTFS" "Linux" "Oba" "Koniec");
PS3="Vyber si OS: "
select hledam in "${hledat[@]}"; do
 case $hledam in
  ${hledat[0]}) e="ntfs-3g"; break;;
  ${hledat[1]}) e="ext[2-4]"; break;;
  ${hledat[2]}) e="ntfs-3g\|ext[2-4]"; break;;
  ${hledat[3]}) exit 2;;
 esac
done

arr=$(grep "$e" /etc/fstab)
if [ "$arr" == "" ]
then
 echo "No line found!"
 exit 1
fi
echo "Vyber radek k editaci"
OLDIFS=$IFS
IFS=$'\n'
PS3="Vyber si riadok: "
select array in $arr
do
  line="$array"
  break
done
IFS=$OLDIFS

#echo "Vybraty riadok: $line"
dir=`echo $line|awk '{print $2}'`
if [[ "$dir" =~ "^/\|/home\|/swap$" ]]
then
 echo "Nemozno menit adresar $dir"
 exit 3
else
 echo "Upraveny fstab by vyzeral takto:"
 awk --assign=riadok="$line" '{if ($0 == riadok) {$0="prepisany riadok"};print}' /etc/fstab
fi

webhope

Re: Nahrazení řetězce pomocí reg. výrazu
« Odpověď #7 kdy: 20. 03. 2010, 17:35:06 »
To je sice pěkné, že si to přepsal celé jinak, ale já bych rád dořešil ten svůj kód, ať se toho mohu nějak poučit. Jde mi o to nahrazení přes regul. výraz a předání proměnné mimo cyklus, který jsem uvedl. Tzn. aby se mi ta proměnná neztratila/nevynulovala.

deadmail

Re: Nahrazení řetězce pomocí reg. výrazu
« Odpověď #8 kdy: 21. 03. 2010, 04:34:44 »
Ak chceme zmenit riadok cislo, tak sa to da urobit rychlo:

Kód: [Vybrat]
read -p "Vyber cislo riadku: " number

grep "ext[2-4]" /etc/fstab | awk --assign=number="$number" '{if (NR == number) print "tak totok je prepsana radka"; else print}' #pomocou awk

grep "ext[2-4]" /etc/fstab | sed "${number}s/.*/tak toto je zmeneny riadok/" #cez sed

Kód: [Vybrat]

Na zistenie kazdej premennej spustat novy awk na ten isty text a potom robit nahradzovanie v bashi je dost prekomplikovane ... no ale co sa tyka while, tak problem je  s pipe-ou (|), spusta sa novy proces a preto premennu dalej v skripte "nevidno". Ak sa v cykle nic nevypisuje, tak sa to da obist vypisanim hodnotu a priradenim celeho prikazu (prem=$(grep| while ...)) do premennej. Druha moznost je spustit while a presmerovat mu vstup bez pipe:

Kód: [Vybrat]
while read line
do
 riadok=$line
done < <(grep "ext[2-4]" /etc/fstab)
echo $riadok #vypise posledny riadok s ext?

webhope

Re: Nahrazení řetězce pomocí reg. výrazu
« Odpověď #9 kdy: 21. 03. 2010, 07:21:28 »
Deadmail: Ten poslední kód cos napsal je pecka. Ale co znamená " < <" . Proč tam jsou dvě menšítka a ne jedno?

Já jsem si toho už všiml a tak jsem to opravil. Akordád jsem to už včera sem nevložil. Napsal jsem tuto předlohu:

Kód: [Vybrat]
pattern=`echo $line | awk  '{print $1"[:space:]*"$2"[:space:]*"$3"[:space:]*"$4"[:space:]*"$5"[:space:]*"$6}'` # stara hodnota - dostat A tímto jsem to zkousel nahradit:
Kód: [Vybrat]
echo ${path_name##/*/replacement}

No a to mi nefunguje. Nenahradi to. Chybovou hlasku uz nepise.

Kód: [Vybrat]
pattern=`echo $line | awk  '{print $1""}'` # zkousel jsem i zjednodusenou variantu
pattern=`echo "UUID=2090ACC103B52D41 /media/win_c ntfs-3g defaults,umask=000 0 0" | awk  '{print $1}'` # a zkousel jsem pro vytvoreni predlohy doplnit text primo
replacement="zameneny retezec - pokus - "
replaced=${line//pattern#/replacement};
replacement="asdasdasddd"
echo ${path_name##/*/replacement}
read

Edit:
Můžeš mi prosímtě ještě vysvětlit co znamená to ext[2-4] v grepu. Respektive co znamená to ext. Pres info a man jsem o tom  nenasel nic.
« Poslední změna: 21. 03. 2010, 07:29:41 od webhope webhope »

deadmail

Re: Nahrazení řetězce pomocí reg. výrazu
« Odpověď #10 kdy: 22. 03. 2010, 07:02:08 »
"ext[2-4]" je regularny vyraz (Regular Expression) zastupujuci retazce, kde prve tri znaky su e, x a t, stvrty znak je z rozsahu 2-4, teda zastupuje 3 retazce ext2, ext3, ext4 (linuxove filesystemy). Viac napr. aj v seriali o RE tu na root-e.

Presmerovania (redirection):
prikaz <subor ... obsah suboru je vstupom prikazu
prikaz1 $(prikaz2), prikaz1 `prikaz2` ... spusti prikaz2 a jeho vystup zapise ako parametre pre prikaz1
prikaz1 <(prikaz2) ... spusti prikaz2, vystup zapise do docasneho suboru a potom ako parameter pre prikaz1 da nazov tohto docasneho suboru
prikaz1 | prikaz2 ... vstupom prikaz2 je vystup prikaz1 (rura, pipe)
prikaz1 < <(prikaz2) ... vystup prikaz2 sa zapise do docasneho suboru a ten subor sa da ako vstup pre prikaz1 (teda prepojenie ako cez ruru)

webhope

Re: Nahrazení řetězce pomocí reg. výrazu
« Odpověď #11 kdy: 22. 03. 2010, 07:53:17 »
Regulární výrazy už znám, ale tohle ačkoliv je to základ, mi nějak nedošlo. Ty další věci, díky, některé už znám a ty další, zkusím si to nějak zapamatovat. Nepřišel si na to přič mi nefunguje to nahrazování? paterrn//var/replace ? To je tak poslední věc co potřebuju vyřešit. Se zbytkem bych si už pohrál sám. Díkes
« Poslední změna: 22. 03. 2010, 08:14:20 od webhope webhope »

deadmail

Re: Nahrazení řetězce pomocí reg. výrazu
« Odpověď #12 kdy: 22. 03. 2010, 09:28:48 »
Co som pozeral, tak stale hladas text "pattern" a nie podla hodnoty premennej (chyba $ pred nazvom).

Vypis riadku so zmenenim tretieho pola sa da urobit napr. takto (funguje ak v riadku nie su rovnake polia  a pole neobsahuje znak "/"):
Kód: [Vybrat]
line="UUID=2090ACC103B52D41 /media/win_c ntfs-3g defaults,umask=000 0 0"
pattern=`echo $line|awk '{print $3}'`
zmena="ext2"
echo ${line/$pattern/$zmena}

Aby to fungovalo aj pre druhy stlpec (obsahuje lomitko), tak treba upravit=escapovat lomitko, napr. prikazom (medzi riadky pattern a echo)
Kód: [Vybrat]
pattern=${pattern//\//\\\/} # nahrad vsetky / znakmi \/

webhope

Re: Nahrazení řetězce pomocí reg. výrazu
« Odpověď #13 kdy: 22. 03. 2010, 11:37:19 »
Já myslel, že když tam je ${} tak dovnitř už se dolar nepíše. Tak jsem si to asi s něčím spletl. Ta záměna lomítek mě taky napadla, ale jelikož nefungovalo to nahrazování, tak jsem to nezkoušel. Díky.

webhope

Re: Nahrazení řetězce pomocí reg. výrazu
« Odpověď #14 kdy: 23. 03. 2010, 08:34:39 »
Tak tady je moje řešení:

Kód: [Vybrat]
n=0;echo "Vyber radek k editaci:"; read number; clear; echo -e "Vybral si radek:";
  number=$number; # pokud to neulozim tak se promenna pri dalsim read vymaze
  pattern=$( grep $e /etc/fstab | while read line; do
let "n += 1";
if [ "$n" == "$number" ]; then  # POCET OD NULY
  dir_=`echo $line | awk  '{print }'` # stara hodnota - dostat promennou z awk do bashe
  if [ "$dir_" == "/" ]; then escape=1; echo "Bod / pro pripojeni systemoveho oddilu neni povoleno nastavit."; fi;
  if [ "$dir_" == "/home" ]; then escape=1; echo "Bod /home neni povoleno nastavit."; fi;
  if [ "$dir_" == "swap" ]; then escape=1; echo "Oddil swap neni povoleno nastavit."; fi;
  #awk -v w="$line" '{print w}'# dostat promennou do awk
  echo "$line" | awk '{print $1," \033[1;32m",$1,"\033[1;36m", $3, "\033[1;0m", $4, $5}';
  echo "TOTO_JE_JEN_ODDELOVAC_KTERY_ODDELI_HLASKU_OD_PREDLOHY_SAMOTNE";
  echo $line | awk  '{print $1"[:space:]*"$1"[:space:]*"$3"[:space:]*"$4"[:space:]*"$5"[:space:]*"$6}' # stara hodnota - dostat promennou z awk do bashe
fi;
    done)
    hlaska=${pattern%TOTO_JE_JEN_ODDELOVAC_KTERY_ODDELI_HLASKU_OD_PREDLOHY_SAMOTNE*} # smazat od konce (od posledního výskytu)
    pattern=${pattern#*TOTO_JE_JEN_ODDELOVAC_KTERY_ODDELI_HLASKU_OD_PREDLOHY_SAMOTNE} # smazat od začátku (od prvního výskytu)
    echo -e $hlaska;
    echo $pattern;
    read

Možná složitější,ale je moje :-)
« Poslední změna: 23. 03. 2010, 09:38:15 od webhope webhope »