Страница 1 из 2
про awk и shell
Добавлено: 2010-05-16 1:39:37
Reiser
Можно ли как-то получить внутри одного 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 " "?
Re: про awk и shell
Добавлено: 2010-05-16 11:41:40
Гость
пример неполный (test.sh, file.in, $protein из родительского скрипта). Наверное, можно обойтись одним скриптом на awk.
А так, переменные можно передать с помощью опции -v.
Re: про awk и shell
Добавлено: 2010-05-16 13:20:34
Reiser
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 при каждом вызове разные, потому и переменные.
Re: про awk и shell
Добавлено: 2010-05-16 13:29:13
Reiser
Насчёт 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, соответственно, оно ничего не выдаёт в ответ.
Re: про awk и shell
Добавлено: 2010-05-16 13:31:31
Reiser
И в чём разница между awk ' ' и awk " "?
Re: про awk и shell
Добавлено: 2010-05-16 14:08:34
Reiser
Кусок рабочего файла:
Код: Выделить всё
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
Re: про awk и shell
Добавлено: 2010-05-16 15:11:07
Reiser
Почему-то происходит странная передача параметра. Если запустить такое:
то на выходе будет
...
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
Гость
$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().
Re: про awk и shell
Добавлено: 2010-05-17 3:57:38
Reiser
Думаю, Вы правы. Но, также думаю, что вместо массива p[] сформированный ответ можно загнать в одну переменную сразу же, до вызова getline.
Re: про awk и shell
Добавлено: 2010-05-17 9:03:20
Reiser
Вариант с 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"
впрочем, 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) экранирование одинарной кавычки внутри одинарных ковычек делается через одно место ;\
Добавлено: 2010-05-21 2:54:29
Reiser
Код: Выделить всё
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
Re: про awk и shell
Добавлено: 2010-05-21 10:32:12
Reiser
Внезапно, m[FNR] заработало. Но при печати приходится ставить "m["'FNR'"]=" m[FNR] чтобы было m[256]=J.
Самое интересное, что если внутри первого цикла, сразу после row=FNR нарисовать mm=mm"_"m["'FNR'"] - то эта переменная существует весь скрипт.
ps. Рискую вылезти в оффтопик и нарваться на маны, но чем принципиально отличается ассоциативный массив от линейного? Я же могу и так и так обратится к элементу m[x]?
Re: про awk и shell
Добавлено: 2010-05-21 10:54:02
Reiser
Да, сначала "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].
Re: про awk и shell
Добавлено: 2010-05-23 12:10:27
Reiser
Столкнулся с проблемой:
Код: Выделить всё
#! /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 }'
Re: про awk и shell
Добавлено: 2010-05-23 17:55:06
Reiser
Спасибо. Непонятно, почему меня предлагается игнорить. Если есть хороший самоучитель по тонкостям shell с примерами в свободном доступе, желательно на русском языке - буду с удовольствием мучать его, а не вас.