bash awk $4

На самом деле это единственный раздел про unix на этом форуме

Модераторы: /dev/random, Модераторы разделов

Аватара пользователя
lgar
Сообщения: 118
ОС: Ubuntu

bash awk $4

Сообщение lgar »

Есть скрипт, в который попадают внешние команды, некоторые команды содержат awk, в awk есть $4, так как bash воспринимает это как позиционный элемент, на выходе получается не то, что хотелось.

Простой пример:


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

$ ssh -q -t e1 sudo -s mailq | awk '{print $4}' | grep '.' | sort | uniq -c | sort -n


В скрипте (вывод bash -x):

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

ssh -q -t e1 sudo -s mailq '|' awk ''\''{print' '}'\''' '|' grep ''\''.'\''' '|' sort '|' uniq -c '|' sort -n


Как можно избежать такой ситуации?
Спасибо сказали:
Аватара пользователя
/dev/random
Администратор
Сообщения: 5511
ОС: Gentoo

Re: bash awk $4

Сообщение /dev/random »

lgar писал(а):
06.08.2012 19:32
Простой пример:

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

$ ssh -q -t e1 sudo -s mailq | awk '{print $4}' | grep '.' | sort | uniq -c | sort -n


В скрипте (вывод bash -x):

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

ssh -q -t e1 sudo -s mailq '|' awk ''\''{print' '}'\''' '|' grep ''\''.'\''' '|' sort '|' uniq -c '|' sort -n

Вы явно что-то недоговариваете. Эта команда (в том виде, как приведена) не может дать такого вывода bash -x. Обратите внимание, например, что в этом выводе экранированы пайпы, а в команде - нет. Приведите, пожалуйста, фрагмент скрипта.
Спасибо сказали:
Аватара пользователя
lgar
Сообщения: 118
ОС: Ubuntu

Re: bash awk $4

Сообщение lgar »

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

for hostserv in $(for i in `echo "${server[@]}"`; do echo $i; done | sort | uniq); do echo $hostserv; ssh $hostserv "eval $sudo $su ${cmd[@]}"; done


Где server - список серверов, hostserv имя сервера в цикле, $sudo $su - переменные, устанавливающие режим работы sudo -s или sudo

Команду содержит массив ${cmd[@]}

Возможно, можно вывести через echo весь массив так, например, используя кавычки (одинарные явно не подошли), потом каким-нибудь волшебным образом передать в ssh, или вместо echo использовать printf


/dev/random писал(а):
06.08.2012 19:54
lgar писал(а):
06.08.2012 19:32
Простой пример:

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

$ ssh -q -t e1 sudo -s mailq | awk '{print $4}' | grep '.' | sort | uniq -c | sort -n


В скрипте (вывод bash -x):

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

ssh -q -t e1 sudo -s mailq '|' awk ''\''{print' '}'\''' '|' grep ''\''.'\''' '|' sort '|' uniq -c '|' sort -n

Вы явно что-то недоговариваете. Эта команда (в том виде, как приведена) не может дать такого вывода bash -x. Обратите внимание, например, что в этом выводе экранированы пайпы, а в команде - нет. Приведите, пожалуйста, фрагмент скрипта.
Спасибо сказали:
Аватара пользователя
/dev/random
Администратор
Сообщения: 5511
ОС: Gentoo

Re: bash awk $4

Сообщение /dev/random »

lgar писал(а):
06.08.2012 20:39

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

for hostserv in $(for i in `echo "${server[@]}"`; do echo $i; done | sort | uniq); do echo $hostserv; ssh $hostserv "eval $sudo $su ${cmd[@]}"; done

Ох, вот это вы наворотили вложенного парсинга...
Удалённый шелл в ssh, eval, su, присваивание массива (которое вы не привели), плюс я не помню, выполняет ли парсинг sudo.
При каждом парсинге убирается один уровень экранирования и подставляются переменные.

Можно, конечно, просчитать нужное количество экранирующих символов, но это всё равно, что на brainfuck'е писать. Тем более, насколько я понял, sudo и su у вас могут быть, а могут не быть, и это означает разное количество бэкслэшей. Лучше всего упростите код. Например, я не вижу, зачем вам выполнять awk удалённо. Если возможно, попробуйте свести всё к
ssh "$hostserv" "$VERY_simple_command" | обработка | обработка
где удалённо выполняется только очень простая команда, целиком находящаяся в одной переменной.
Спасибо сказали:
Аватара пользователя
SLEDopit
Модератор
Сообщения: 4824
Статус: фанат консоли (=
ОС: GNU/Debian, RHEL

Re: bash awk $4

Сообщение SLEDopit »

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

for hostserv in $(for i in `echo "${server[@]}"`; do echo $i; done | sort | uniq); do
echo $hostserv; ssh $hostserv "eval $sudo $su ${cmd[@]}"; done


замените все for на while и будет вам счастье:

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

echo "${server[@]}" | tr ' ' '\n' | sort -u | while read hostserv
do ; echo $hostserv; ssh $hostserv "$sudo $su ${cmd[@]}"; done

eval в данном случае и не нужен, по-моему. и без него всё прекрасно будет работать.

/dev/random писал(а):
06.08.2012 21:38
Например, я не вижу, зачем вам выполнять awk удалённо.
Сэкономить на трафике? (:
UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity. © Dennis Ritchie
The more you believe you don't do mistakes, the more bugs are in your code.
Спасибо сказали:
Аватара пользователя
lgar
Сообщения: 118
ОС: Ubuntu

Re: bash awk $4

Сообщение lgar »

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

echo "${server[@]}" | tr ' ' '\n' | sort -u | while read hostserv
do
  echo $hostserv; ssh $hostserv "$sudo $su ${cmd[@]}";
done


Это не очень помогло, так как заходит на 1 сервер из списка, на остальные не заходит, хотя если убрать ssh, оставить echo hostserv. то выполняется до конца. Это ладно, тут уж мне самому смотреть, while выполняется пока read может читать входной поток, тут ssh как-то ему мешает. . Вопрос сузился до следующего, как экранировать $ ?
Получается так, что bash считает это позиционным элементом, поэтому уже в массив он приходит пустой, поэтому такая конструкция не действует.

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

VAR=$(echo ${cmd[@]} | sed "s/\$/\\\\\$/g"); echo -e $VAR;


Задавать что-то вроде $4='$4' неправильно, так как позиционные элементы тоже используются.

Итог остался такой, что необходимо вручную экранировать этот символ, вводя команду в командной строке.

Спасибо сказали:
Аватара пользователя
KiWi
Бывший модератор
Сообщения: 2521
Статус: статус, статус, статус

Re: bash awk $4

Сообщение KiWi »

ssh -n.
Спасибо сказали: