LinuxForum.Fans
Тема

Помогите написать скрипт на Bash. Подмена значений .

Автор: borisgorbunov 19 сообщений 4477 просмотров
07.10.2014 12:51 · отредактировано #395333

Есть папка с файлами . В каждом файле есть данные в виде:
------------------------------------------------------------------------------------------------------------------
HOLE = KZK_249 /*
PROJECT = Yark_wdb_int@pnsmos5 /*
DEPTH_BOTTOM = - /* Downhole depth (METRES) DOUBLE
DRILLED_DEPTH = - /* Total Depth - Driller (METRES) DOUBLE
ELEV_MEAS_REF = 181.43 /* Elevation of Measurement Reference (METRES) DOUBLE
FIELD = Jarkeevsky /* Field
LOCATION = Kjizjil-Kjychevskaja /* Location
LOGGED_DEPTH = - /* Total Depth - Logger (METRES) DOUBLE
SYMBOL = CIRCLE /* Symbol
TVD_BOTTOM = - /* True Vertical Depth at well bottom (METRES) DOUBLE
TYPE = SPM /*
WELL_BASH = 249KZK /* Primary Well Identifier
--------------------------------------------------------------------------------------------------------------------

Нужно подменить значение в строчке HOLE = KZK_249 /* от знака равно до слэша, на значение из строчки WELL_BASH = 249KZK /* Primary Well Identifier от знака равно до слэша. Причем в каждом файле значения разные. А их 1000 шт.
Прошу выручайте . *SORRY*

07.10.2014 13:02 #395338

Интересный вопрос. Было бы тоже интересно узнать, как это делается...ждём железобетонного суперадминистратора всех Linux-Вселенных, мегагуру bash-scripting'a drBatty.

07.10.2014 14:09 · отредактировано #395357
chelovekot написал:
Интересный вопрос. Было бы тоже интересно узнать, как это делается...ждём железобетонного суперадминистратора всех Linux-Вселенных, мегагуру bash-scripting'a drBatty.

Это 5 *ROFL*
Но при этом согласен, drBatty это толковый специалист.

07.10.2014 14:36 · отредактировано #395367

часть первая:

text

a=`grep HOLE file|awk '{print $3}'`
b=`grep WELL_BASH file|awk '{print $3}'`
sed -ri 's/'$a'/'$b'/g' file 

часть вторая:
если есть список файлов,то можно все это дело в завернуть в цикл.

как то так:

text

for i in `cat list`;do sed -ri 's/'$a'/'$b'/g' $i;done

где list список с файлами.
Эту часть не проверял, но первая часть точно работает.

ед-е условие HOLE и WELL_BASH , должны встречаться один раз в файле.

07.10.2014 14:38 #395368

Причем в каждом файле значения разные., значения a и b надо будет каждый роа обнулять на новые)

p.s. это я что то упустил.

07.10.2014 14:49 #395373
i2ks написал:
Причем в каждом файле значения разные., значения a и b надо будет каждый роа обнулять на новые)

p.s. это я что то упустил.

Ну да в этом и загвоздка.

07.10.2014 15:15 · отредактировано #395386

Я решил извращнуться на awk=)) как обычно=)

text
tac rep.txt |awk -F[=\ ] '{if(index($0,"WELL_BASH")>0){WB=$4};gsub(/HOLE = [a-Z]*_[0-9]*/,"HOLE = "WB); print $0}'|tac

тут правда с учётом того что вид у HOLE всегда типа
HOLE = [a-Z]*_[0-9]* ну с этим можно поиграться...
Теперь вопрос как прореплейсить файлы если это необходимо=)

07.10.2014 15:16 #395387
"i2ks" написал:
Причем в каждом файле значения разные., значения a и b надо будет каждый роа обнулять на новые)

p.s. это я что то упустил.

А в чем сложность то? делайте это внутри цикла :)

07.10.2014 15:21 · отредактировано #395389

сделал два файла

text

$ ls -l
total 8
-rw-rw-r-- 1 526 Oct  7 15:16 file1
-rw-rw-r-- 1 528 Oct  7 15:16 file2

содержание файлов:

text

$ cat file1
HOLE = KZK_249 /*
PROJECT = Yark_wdb_int@pnsmos5 /*
DEPTH_BOTTOM = - /* Downhole depth (METRES) DOUBLE
DRILLED_DEPTH = - /* Total Depth - Driller (METRES) DOUBLE
ELEV_MEAS_REF = 181.43 /* Elevation of Measurement Reference (METRES) DOUBLE
FIELD = Jarkeevsky /* Field
LOCATION = Kjizjil-Kjychevskaja /* Location
LOGGED_DEPTH = - /* Total Depth - Logger (METRES) DOUBLE
SYMBOL = CIRCLE /* Symbol
TVD_BOTTOM = - /* True Vertical Depth at well bottom (METRES) DOUBLE
TYPE = SPM /*
WELL_BASH = 249KZK /* Primary Well Identifier

и

$ cat file2 HOLE = KZK_2409 /* PROJECT = Yark_wdb_int@pnsmos5 /* DEPTH_BOTTOM = - /* Downhole depth (METRES) DOUBLE DRILLED_DEPTH = - /* Total Depth - Driller (METRES) DOUBLE ELEV_MEAS_REF = 181.43 /* Elevation of Measurement Reference (METRES) DOUBLE FIELD = Jarkeevsky /* Field LOCATION = Kjizjil-Kjychevskaja /* Location LOGGED_DEPTH = - /* Total Depth - Logger (METRES) DOUBLE SYMBOL = CIRCLE /* Symbol TVD_BOTTOM = - /* True Vertical Depth at well bottom (METRES) DOUBLE TYPE = SPM /* WELL_BASH = 249KZ0K /* Primary Well Identifier

далее в цикле все:

text

for i in `ls -1`;do  b=`grep WELL_BASH $i|awk '{print $3}'`; a=`grep HOLE $i|awk '{print $3}'`;sed 's/'$a'/'$b'/g' $i;done

результат:

text

HOLE = 249KZK /*
PROJECT = Yark_wdb_int@pnsmos5 /*
DEPTH_BOTTOM = - /* Downhole depth (METRES) DOUBLE
DRILLED_DEPTH = - /* Total Depth - Driller (METRES) DOUBLE
ELEV_MEAS_REF = 181.43 /* Elevation of Measurement Reference (METRES) DOUBLE
FIELD = Jarkeevsky /* Field
LOCATION = Kjizjil-Kjychevskaja /* Location
LOGGED_DEPTH = - /* Total Depth - Logger (METRES) DOUBLE
SYMBOL = CIRCLE /* Symbol
TVD_BOTTOM = - /* True Vertical Depth at well bottom (METRES) DOUBLE
TYPE = SPM /*
WELL_BASH = 249KZK /* Primary Well Identifier
HOLE = 249KZ0K /*
PROJECT = Yark_wdb_int@pnsmos5 /*
DEPTH_BOTTOM = - /* Downhole depth (METRES) DOUBLE
DRILLED_DEPTH = - /* Total Depth - Driller (METRES) DOUBLE
ELEV_MEAS_REF = 181.43 /* Elevation of Measurement Reference (METRES) DOUBLE
FIELD = Jarkeevsky /* Field
LOCATION = Kjizjil-Kjychevskaja /* Location
LOGGED_DEPTH = - /* Total Depth - Logger (METRES) DOUBLE
SYMBOL = CIRCLE /* Symbol
TVD_BOTTOM = - /* True Vertical Depth at well bottom (METRES) DOUBLE
TYPE = SPM /*
WELL_BASH = 249KZ0K /* Primary Well Identifier

как видите все работате.

только у меня просто вывод, а надо еще добавить будет ключик -ri после слова sed

07.10.2014 15:23 #395391

"beliy" написал:
А в чем сложность то? делайте это внутри цикла
ни в чем)
07.10.2014 15:46 · отредактировано #395400

Да без sed какай то жопа типа:

text
for file in *.txt; do tac $file|awk -F[=\ ] '{if(index($0,"WELL_BASH")>0){WB=$4};gsub(/HOLE = [a-Z]*_[0-9]*/,"HOLE = "WB); print $0}'|tac > new_$file; mv new_$file $file; done
07.10.2014 16:13 #395406

Огромное спасибо всем. Беру сие творения на заметку. *YES*

07.10.2014 16:18 #395407
i2ks написал:
сделал два файла
text

for i in `ls -1`;do  b=`grep WELL_BASH $i|awk '{print $3}'`; a=`grep HOLE $i|awk '{print $3}'`;sed 's/'$a'/'$b'/g' $i;done

только у меня просто вывод, а надо еще добавить будет ключик -ri после слова sed

for i in `ls -1`;do b=`grep WELL_BASH $i|awk '{print $3}'`; a=`grep HOLE $i|awk '{print $3}'`;sed -ri 's/'$a'/'$b'/g' $i;done

Вот так ???

07.10.2014 16:51 #395411

"borisgorbunov" написал:
Вот так ???
да, может на 10ке файлов это проверить. :-)
07.10.2014 18:21 #395438
"borisgorbunov" написал:
for i in `ls -1`;do  b=`grep WELL_BASH $i|awk '{print $3}'`; a=`grep HOLE $i|awk '{print $3}'`;sed -ri 's/'$a'/'$b'/g' $i;done
"i2ks" написал:
a=`grep HOLE file|awk '{print $3}'`
b=`grep WELL_BASH file|awk '{print $3}'`
sed -ri 's/'$a'/'$b'/g' file
"i2ks" написал:
for i in `ls -1`;do b=`grep WELL_BASH $i|awk '{print $3}'`; a=`grep HOLE $i|awk '{print $3}'`;sed 's/'$a'/'$b'/g' $i;done

как же иногда хочется ходить по улицам и убивать людей, которые в одной строке мешают sed, grep и awk... хорошо хоть тут tr и cut не понадобились... =)

наиболее разумное решение, ИМХО:

text
find -type f | while read f; do 
  well_bash=$(sed -rne 's!^WELL_BASH\s=\s(.+)\s/\*.*$!\1!p' $f)
  sed -re 's!^(HOLE\s=\s).+(\s/\*.*)$!\1'"$well_bash"'\2!'  -i  $f
done

ради спортивного интереса, одним sed скриптом:

text
sed -nre 'H;/WELL_BASH/{x;s!(HOLE\s*=\s*)([^\n]+)(\s*/\*[^\n]*\n.*\nWELL_BASH\s*=\s*)([^\n]+)(\s*/\*[^\n]*\n)!\1\4\3\4\5!;p}' <file>

само собой, у каждого способа есть свои недостатки...

07.10.2014 18:27 #395442
Fat-Zer написал:
как же иногда хочется ходить по улицам и убивать людей, которые в одной строке мешают sed, grep и awk... ...

Ну ты тут не одинок...

07.10.2014 19:10 #395444

Да обосраться можно, все такие умные.

10.10.2014 14:12 #395795

borisgorbunov,
как-то так:
[console]$ sed -rn 'H;${x;s~(HOLE =)([^/]*)(.*)(WELL_BASH =)([^/]*)~\1\5\3\4\5~;s/\n//;p}' f
HOLE = 249KZK /*
PROJECT = Yark_wdb_int@pnsmos5 /*
DEPTH_BOTTOM = - /* Downhole depth (METRES) DOUBLE
DRILLED_DEPTH = - /* Total Depth - Driller (METRES) DOUBLE
ELEV_MEAS_REF = 181.43 /* Elevation of Measurement Reference (METRES) DOUBLE
FIELD = Jarkeevsky /* Field
LOCATION = Kjizjil-Kjychevskaja /* Location
LOGGED_DEPTH = - /* Total Depth - Logger (METRES) DOUBLE
SYMBOL = CIRCLE /* Symbol
TVD_BOTTOM = - /* True Vertical Depth at well bottom (METRES) DOUBLE
TYPE = SPM /*
WELL_BASH = 249KZK /* Primary Well Identifier
[/console]
это в предположении, что WELL_BASH всегда идёт ПОСЛЕ HOLE.
Если ДО, то проще.

10.10.2014 14:18 #395796
"chelovekot" написал:
мегагуру bash-scripting'a drBatty.

тут лучше sed.

"i2ks" написал:
for i in `cat list`

ну нахрена жеж?!

text
while  read line; do …; done <list
"i2ks" написал:
ед-е условие HOLE и WELL_BASH , должны встречаться один раз в файле.

в моём решении выше может сколько угодно раз, меняется первое HOLE на последнее WELL.

"tmp13" написал:
tac rep.txt

тоже интересный вариант.

"Fat-Zer" написал:
sed -nre 'H;/WELL_BASH/{x;s!(HOLE\s*=\s*)([^\n]+)(\s*/\*[^\n]*\n.*\nWELL_BASH\s*=\s*)([^\n]+)(\s*/\*[^\n]*\n)!\1\4\3\4\5!;p}' <file>

хм. Опередили.

Войдите или зарегистрируйтесь, чтобы ответить.