про awk и shell

Программирование на sh, быть может немного про альтернативные языки
Правила форума
Убедительная просьба юзать теги [code] при оформлении листингов.
Сообщения не оформленные должным образом имеют все шансы быть незамеченными.
Reiser
рядовой
Сообщения: 22
Зарегистрирован: 2010-04-21 17:28:07

про awk и shell

Непрочитанное сообщение Reiser » 2010-05-16 1:39:37

Можно ли как-то получить внутри одного awk результаты запуска второго, причём с переменными из первого awk?
Например, подобное:

Код: Выделить всё

gawk "{
if (  index (\"$protein\", \$3) && ! index (\"$protein\", \$6)) {printf \"%s %s %s \t%s %s %s %s %s\", \$1, \$2, \$3, \$4, \$5, \$6, \$7, `test3.sh \$3 \$5`}
}" file.in
ругается на параметры $3 и $5 в конце скрипта.
Как во "внутренний" awk корректно передать параметры из "внешнего"?зависит ли это от версии bash? Как вообще влияют на разбор скрипта кавычки gawk " " и gawk " "?

Хостинговая компания Host-Food.ru
Хостинг HostFood.ru
 

Услуги хостинговой компании Host-Food.ru

Хостинг HostFood.ru

Тарифы на хостинг в России, от 12 рублей: https://www.host-food.ru/tariffs/hosting/
Тарифы на виртуальные сервера (VPS/VDS/KVM) в РФ, от 189 руб.: https://www.host-food.ru/tariffs/virtualny-server-vps/
Выделенные сервера, Россия, Москва, от 2000 рублей (HP Proliant G5, Intel Xeon E5430 (2.66GHz, Quad-Core, 12Mb), 8Gb RAM, 2x300Gb SAS HDD, P400i, 512Mb, BBU):
https://www.host-food.ru/tariffs/vydelennyi-server-ds/
Недорогие домены в популярных зонах: https://www.host-food.ru/domains/

Гость
проходил мимо

Re: про awk и shell

Непрочитанное сообщение Гость » 2010-05-16 11:41:40

пример неполный (test.sh, file.in, $protein из родительского скрипта). Наверное, можно обойтись одним скриптом на awk.

А так, переменные можно передать с помощью опции -v.

Reiser
рядовой
Сообщения: 22
Зарегистрирован: 2010-04-21 17:28:07

Re: про awk и shell

Непрочитанное сообщение Reiser » 2010-05-16 13:20:34

test.sh

Код: Выделить всё

awk '
NR=='$3'+15 { printf "%s %s %s %s", $1, $2, $4, $5 }      #выдаёт на выход строку с номером $3+15
' conservation/$1/$2/consurf.grades                       #в $1 и $2 передаётся адрес файла
содержание файла conserf.grades особого смысла не несёт.
$1 и $2 при каждом вызове разные, потому и переменные.

Reiser
рядовой
Сообщения: 22
Зарегистрирован: 2010-04-21 17:28:07

Re: про awk и shell

Непрочитанное сообщение Reiser » 2010-05-16 13:29:13

Насчёт file.in затрудняюсь, т.к. оно используется в большом скрипте и вообще там есть ещё одна строка.
Вопрос только в одном: как внутри awk получить результаты запуска другого awk, которого невозможно запустить заранее из скрипта, т.к. папаметры его запуска долдны быть определены из номеров полей первого awk. Т.е., мета-пример:

Код: Выделить всё

cat file.in | awk 'if bla-bla { print $1, $3, `awk 'if NR==$4 {print}' $2.txt` }'
gawk, например, ругается, что "$1, $3, <- неожиданный конец строки", т.е. $2 и $4 не передаются во вложенный awk, соответственно, оно ничего не выдаёт в ответ.

Reiser
рядовой
Сообщения: 22
Зарегистрирован: 2010-04-21 17:28:07

Re: про awk и shell

Непрочитанное сообщение Reiser » 2010-05-16 13:31:31

И в чём разница между awk ' ' и awk " "?

Reiser
рядовой
Сообщения: 22
Зарегистрирован: 2010-04-21 17:28:07

Re: про awk и shell

Непрочитанное сообщение Reiser » 2010-05-16 14:08:34

Кусок рабочего файла:

Код: Выделить всё

402 DC B 44 TYR A 14.78
402 DC B 297 GLN A 2.71
402 DC B 433 DG C 27.07
402 DC B 432 DG C 2.29
403 DC B 296 SER A 22.37
403 DC B 294 SER A 11.90
403 DC B 297 GLN A 16.23
403 DC B 433 DG C 11.81
403 DC B 432 DG C 26.74
403 DC B 431 DT C 2.74
404 DA B 296 SER A 24.73
404 DA B 432 DG C 18.04
404 DA B 430 DA C 10.79
404 DA B 431 DT C 23.49
405 DT B 258 ILE A 20.09
405 DT B 257 GLY A 14.46
405 DT B 430 DA C 17.97
405 DT B 431 DT C 0.86
405 DT B 255 GLY A 6.52
405 DT B 256 GLY A 5.46
405 DT B 429 DC C 2.33
405 DT B 254 TYR A 0.01
405 DT B 260 ALA A 5.57
405 DT B 261 LYS A 8.84
406 DG B 209 ARG A 18.35
406 DG B 258 ILE A 4.62
406 DG B 239 GLU A 4.29
Запощу-таки весь родительский скрипт:

Код: Выделить всё

if ! test -e test             #создаём папку test, если она не существует
then mkdir test
fi


for i in `ls conservation`; do        #прогоняем по всем папкам, имеющимся в conservation/

list=`ls -F conservation/$i | grep / | sed 's/\///'`      #создаём список list по всем определённым файлам, имеющимся в каждой подпапке conservation/$i/

if ! test -e test/$i                  # создаём папку test/$i, если она не существует
then mkdir test/$i
fi

echo $i > test/$i/info.txt
echo chains: $list >> test/$i/info.txt


protein=    #зануляем в начале цикла

for j in $list
do 
if test -e conservation/$i/$j/consurf.grades      #смысл if: если внутри conservation/$i/$j/ есть consurf.grades - 
then                                              #то добавляем имя подпапки $j к концу $protein
protein=$protein$j                                #можно было сделать через массив, но через index () показалось удобнее
fi
done
echo protein chains: $protein >> test/$i/info.txt     



gawk '{
if (  index ('$protein', $3) && ! index ('$protein', $6)) {print $1, $2, $3, $4, $5, $6, $7, `test3.sh $i $j $3`}
if (! index ('$protein', $3) &&   index ('$protein', $6)) {print $4, $5, $6, $1, $2, $3, $7, `test3.sh $i $j $5`}
}' residue/$i | sort -n | uniq > test/$i/contacts.txt

#смысл: работаем с полями 3 и 6. $protein приобретает перед началом вызова awk значение типа ABD, т.е. некоторое кол-ва лат. заглавных букв.
#Если $3 содержится в $protein, а $6 нет - то выводим строчку как есть (про $0 я в курсе)
#Если $3 не содержится в $protein, а $6 да - то выводим строчку, меняя местами первую и сторую половину
#В конце строки надо приписать рез-т вып. test3.sh, но gawk ругается, что test3 ничего не воводит, т.е. $i и проч. в него не передаются.


echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" >> test/$i/info.txt
done
test3.sh

Код: Выделить всё

awk '
NR=='$3'+15 { print $1, $2, $4, $5 }
' conservation/$1/$2/consurf.grades
кусок consurf.grades:

Код: Выделить всё

   6	   A	  ALA106:A	 1.424		  1	 0.994, 2.317			    1,1			 301/301	F,S,T,N,K,E,V,Q,M,L,A,P,H,D,R,I,G
   7	   C	  CYS107:A	-1.026		  9	-1.035,-1.035			    9,9			 301/301	C
   8	   P	  PRO108:A	-0.273		  6	-0.684,-0.036			    8,5			   9/301	H,P
   9	   V	  VAL109:A	 0.364		  3*	-0.216, 0.994			    6,1			   9/301	A,I,V
  10	   E	  GLU110:A	 2.227		  1	 2.317, 2.317			    1,1			 301/301	S,T,N,K,E,V,Q,M,C,L,A,P,H,D,R,I,G
  11	   S	  SER111:A	 0.463		  3	 0.504, 0.504			    3,3			 301/301	A,S,T,N,K,Y,E,V,H,Q,D,I,G,L
  12	   C	  CYS112:A	-1.026		  9	-1.035,-1.035			    9,9			 301/301	C
  13	   D	  ASP113:A	-0.312		  6	-0.363,-0.216			    7,6			 301/301	A,S,T,W,N,K,E,H,M,D,R,G

Reiser
рядовой
Сообщения: 22
Зарегистрирован: 2010-04-21 17:28:07

Re: про awk и shell

Непрочитанное сообщение Reiser » 2010-05-16 15:11:07

Почему-то происходит странная передача параметра. Если запустить такое:

Код: Выделить всё

i=10MH
gawk '{
{print $0, '`$i`'}
}' 1.txt
то на выходе будет
...
64 TYR A 1 DC B 44.77 10
64 TYR A 1 DC B 51.09 10
64 TYR A 16 DG C 0.00 10
64 TYR A 2 DT B 15.39 10
99 LEU A 1 DC B 19.46 10
99 LEU A 1 DC B 29.57 10
...

вместо
64 TYR A 1 DC B 44.77 10MH


Если же $i вообще текстовая - то ничего не передаётся.
система - FreeBSD 8.0-RELEASE (GENERIC)

Гость
проходил мимо

Re: про awk и shell

Непрочитанное сообщение Гость » 2010-05-16 16:23:22

попробуй так

Код: Выделить всё

#! /bin/sh

i=10MH
gawk '{
{print $0, "'$i'"}
}' 1.txt
символьные строки нужно заклучать в двойные кавычки, иначе awk считает их за переменные и пытается преобразовать

Гость
проходил мимо

Re: про awk и shell

Непрочитанное сообщение Гость » 2010-05-16 16:27:03

Reiser писал(а):И в чём разница между awk ' ' и awk " "?
это есть в sh(1)
sh(1) писал(а): Double Quotes
Enclosing characters within double quotes preserves the literal
meaning of all characters except dollar sign (‘$’), backquote
(‘`’), and backslash (‘\’). The backslash inside double quotes
is historically weird. It remains literal unless it precedes the
following characters, which it serves to quote:
$ ` " \ \n

Гость
проходил мимо

Re: про awk и shell

Непрочитанное сообщение Гость » 2010-05-16 16:47:18

че-то твой скрипт запутанный, без sh -x не обойтись ;) пока попробуй помочь с упрощенным примером
Reiser писал(а):как внутри awk получить результаты запуска другого awk, которого невозможно запустить заранее из скрипта, т.к. папаметры его запуска долдны быть определены из номеров полей первого awk. Т.е., мета-пример:

Код: Выделить всё

cat file.in | awk 'if bla-bla { print $1, $3, `awk 'if NR==$4 {print}' $2.txt` }'
sh(1) преобразовывает строки начиная с самой вложенной. В момент когда родительский awk получает данные awk-ребенок уже завершился. Если каждая инстанция awk оперирует с разным файлом/потоком данных, то тебе наверное придется использовать getline() в одной. Иначе awk придется пускать по нескольку раз, много больше чем ты сейчас пускаешь.

Гость
проходил мимо

Re: про awk и shell

Непрочитанное сообщение Гость » 2010-05-16 16:54:17

Reiser писал(а):

Код: Выделить всё

`awk 'if NR==$4 {print}' $2.txt` }
$4 - это из родительского awk?
$2.txt - из родительского sh или awk? если awk, тот .txt надо было в кавычки загнать

Гость
проходил мимо

Re: про awk и shell

Непрочитанное сообщение Гость » 2010-05-16 17:12:51

хм, получится что-то вроде такого

Код: Выделить всё

cat file.in | awk '
if bla-bla {
    p[1]=$1; p[2]=$2; p[3]=$3; p[4]=$4
    while(getline<p[2]".txt") {
        if (NR==p[4]) c[0]=$0
    }
    print p[1], p[3], c[0]
}'
если поля не загонять в массив, то они сбросятся от вызова getline().

Reiser
рядовой
Сообщения: 22
Зарегистрирован: 2010-04-21 17:28:07

Re: про awk и shell

Непрочитанное сообщение Reiser » 2010-05-17 3:57:38

Думаю, Вы правы. Но, также думаю, что вместо массива p[] сформированный ответ можно загнать в одну переменную сразу же, до вызова getline.

Reiser
рядовой
Сообщения: 22
Зарегистрирован: 2010-04-21 17:28:07

Re: про awk и shell

Непрочитанное сообщение Reiser » 2010-05-17 9:03:20

Вариант с while (getline) не проходит, т.к. после однократного прогона файла с ним уже ничего нельзя сделать, а понадобится его прогнать для следующей строки на поиск соответствия новому NR.

Гость
проходил мимо

Re: про awk и shell

Непрочитанное сообщение Гость » 2010-05-17 13:40:49

ну так засунь getline() подальше, в конец. Или используй getline() повторно, но с FILENAME в качестве файла.

Гость
проходил мимо

Re: про awk и shell

Непрочитанное сообщение Гость » 2010-05-17 13:48:04

в FILENAME awk хранит имя текущего файла, например в след. куске FILENAME="blah.txt"

Код: Выделить всё

awk 'blabla { print }' blah.txt
впрочем, FILENAME не обязательно указывать, getline() оттуда по умолчанию читает: getline < FILENAME == getline

это если я тя правильно понял. Или ты про другую проблему, не относящиюся к значениям $0, $1, $2...?

Гость
проходил мимо

Re: про awk и shell

Непрочитанное сообщение Гость » 2010-05-17 22:38:11

Reiser писал(а):

Код: Выделить всё

gawk "{
if (  index (\"$protein\", \$3) && ! index (\"$protein\", \$6)) {printf \"%s %s %s \t%s %s %s %s %s\", \$1, \$2, \$3, \$4, \$5, \$6, \$7, `test3.sh \$3 \$5`}
}" file.in
кажется я догадался, попробуй так

Код: Выделить всё

gawk "{
if (  index (\"$protein\", \$3) && ! index (\"$protein\", \$6)) {\"test3.sh '\"\$3\"' '\"\$5\"'\" | getline blah; printf \"%s %s %s \t%s %s %s %s %s\", \$1, \$2, \$3, \$4, \$5, \$6, \$7, blah }
}" file.in
- getline blah - сохраняет вывод в переменную blah, не трогая $0, $1, $2...
- \"test3.sh '\"\$3\"' '\"\$5\"'\" - склеивает test.sh, пробел, $3, пробел, $5, где вокруг значения $3 и $5 ставятся одинарные кавычки
- команда рассчитана на вывод только из одно строки, иначе надо пихать внутрь while()

или в более читаемом виде

Код: Выделить всё

gawk -v protein=$protein -v quote=\' '{
if (  index (protein, $3) && ! index (protein, $6)) {"test3.sh "quote$3quote" "quote$5quote | getline blah; printf "%s %s %s \t%s %s %s %s %s", $1, $2, $3, $4, $5, $6, $7, blah }
}' file.in
не надо считать кол-во кавычек ;)

пояснение:
-v quote=\' - в sh(1) экранирование одинарной кавычки внутри одинарных ковычек делается через одно место ;\

Reiser
рядовой
Сообщения: 22
Зарегистрирован: 2010-04-21 17:28:07

Непрочитанное сообщение Reiser » 2010-05-21 2:54:29

Код: Выделить всё

gawk '{
if (FILENAME ~ "residue") {
  m["'FNR'"]="";                      # зануляем элемент массива
  if (  index ("'$prot'", $3) && ! index ("'$prot'", $6)) { m["'FNR'"]=$3 }   # присвоение при выполнении условия
  print NR, FNR, m["'FNR'"]           # проверка присвоения и номера элемента массива
  row=FNR;                            # в конце файла "residue" row будет равно числу строк в этом файле
}

if (FILENAME ~ "conservation") {
  print m["'FNR'"]                    # МЕСТО №1
}

}
END {
for (k=1; k<=row; k++)
{print m["'k"]}                       # МЕСТО №2
}'
ПОЧЕМУ при исполнении данного скрипта в местах №1 и №2 элементы массива m[] равны пустому месту? Как сделать так, чтобы они сохраняли свои значения?

Гость
проходил мимо

Re: про awk и shell

Непрочитанное сообщение Гость » 2010-05-21 8:14:27

- а зачем ты кавычки ставишь вокруг FNR и k? Используй m[FNR] и m[k], если хочешь заполнить линейный массив m[1], m[2], m[3]..., а не ассоциативный массив m["FNR"], m["k"], m["BLAH"], m["etc"]...
- существование m["FNR"] в месте №1 не гарантировано. Ты подаешь сначала "reside" файл и только потом "conservation"? Попробуй сначала что-нить присвоить этой переменной внутри BEGIN {} и посмотри видно ли это на месте №1

Reiser
рядовой
Сообщения: 22
Зарегистрирован: 2010-04-21 17:28:07

Re: про awk и shell

Непрочитанное сообщение Reiser » 2010-05-21 10:32:12

Внезапно, m[FNR] заработало. Но при печати приходится ставить "m["'FNR'"]=" m[FNR] чтобы было m[256]=J.
Самое интересное, что если внутри первого цикла, сразу после row=FNR нарисовать mm=mm"_"m["'FNR'"] - то эта переменная существует весь скрипт.

ps. Рискую вылезти в оффтопик и нарваться на маны, но чем принципиально отличается ассоциативный массив от линейного? Я же могу и так и так обратится к элементу m[x]?

Reiser
рядовой
Сообщения: 22
Зарегистрирован: 2010-04-21 17:28:07

Re: про awk и shell

Непрочитанное сообщение Reiser » 2010-05-21 10:54:02

Да, сначала "reside" файл и только потом "conservation".

Гость
проходил мимо

Re: про awk и shell

Непрочитанное сообщение Гость » 2010-05-21 15:29:05

Reiser писал(а):чем принципиально отличается ассоциативный массив от линейного? Я же могу и так и так обратится к элементу m[x]?
Вообще-то все массивы в awk(1) ассоциативные. Они не имеют длины, но коливество элементов можно посчитать.

Код: Выделить всё

$ awk '
BEGIN {
    for(key in ENVIRON) {
        print "ENVIRON[\""key"\"]=\""ENVIRON[key]"\""
        count++
    }
    print "\nThere are", count, "element(s)"
}'
А вот например: вывести все элементы в промежутке начиная с a["foo"] до a["bar"] не имеет смысла в отличии от с a[1] до a[99].

Reiser
рядовой
Сообщения: 22
Зарегистрирован: 2010-04-21 17:28:07

Re: про awk и shell

Непрочитанное сообщение Reiser » 2010-05-23 12:10:27

Столкнулся с проблемой:

Код: Выделить всё

    #! /bin/sh
    i=ABC
    j=A B C
    gawk 'BEGIN { print '$i', '$j' }'
даёт результат как

Код: Выделить всё

gawk: cmd. line:1: BEGIN {print ABC, A
gawk: cmd. line:1:                    ^ unexpected newline or end of string
Заключение в "" тоже эффекта не даёт. Как напечатать переменную, содержащую пробелы?

Гость
проходил мимо

Re: про awk и shell

Непрочитанное сообщение Гость » 2010-05-23 17:41:18

эм, тебя игнорить? Используй `-v'

Код: Выделить всё

#! /bin/sh
i=ABC
j="A B C"
awk 'BEGIN { print "'"$i"'", "'"$j"'" }'
awk -v i=$i -v j="$j" 'BEGIN { print i, j }'

Reiser
рядовой
Сообщения: 22
Зарегистрирован: 2010-04-21 17:28:07

Re: про awk и shell

Непрочитанное сообщение Reiser » 2010-05-23 17:55:06

Спасибо. Непонятно, почему меня предлагается игнорить. Если есть хороший самоучитель по тонкостям shell с примерами в свободном доступе, желательно на русском языке - буду с удовольствием мучать его, а не вас.