Толик Панков
hex_laden
............ .................. ................

October 2030
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31

Back January 22nd, 2020 Forward
Записать вывод awk в несколько переменных bash

Или как раскидать результат работы awk по нескольким переменным.

Преамбула


Предположим, у нас есть некоторая таблица в виде файла CSV с набором полей, например таких Login,FullName,Phone,Room,WorkTime и разделителем полей , (запятая):

verb666,Misha Verbitsky,+415314499922,42,11:00-16:00
ktvs421,Vasiliy Kotov,+415314499966,77a,00:00-06:00
dkldn89,Dmitry Kaledin,+415314499949,65b,22:00-00:00
vfurry1,Veniamin Furman,+415314499900,99,12:20-19:25
tpunk56,Tolik Punkoff,+415314499911,59,00:00-11:00


Нужно вытащить из нее некоторые данные, и далее как-либо обработать. Вытащить данные можно с помощью awk, используя оператор print, но возникает вопрос, как передать данные обратно в bash.

Предположим, что заголовок удален, в файле остались только данные.

awk и eval


В bash есть встроенная команда eval, преобразующая переданную ей строку в команду или набор команд оболочки, и запускающая ее на выполнение. Этим и воспользуемся.

1. Организуем цикл, в котором будем производить обработку данных:

IFS_=$IFS
IFS=$'\n'
for TMPSTRING in $(cat "demotable.txt")
do
#тут будет код
done
IFS=$IFS_


Перед циклом я подправил переменную $IFS содержащую глобальные разделители, в нее, в частности, "смотрят" операторы циклов, чтобы определить, где начинается следующий элемент. По умолчанию переменная $IFS содержит пробел, табуляцию и перевод строки, но поскольку у нас есть данные с пробелом, то это не подходит, цикл будет работать неверно. Потому сохраняем старое значение во временную переменную, устанавливаем новое значение в перевод строки (\n). После цикла возвращаем значение на место.
В цикле организуем разбор данных:

echo "$TMPSTRING"|awk -F "," '{print "LOGIN=" $1; print "FULLNAME=" $2
print "PHONE=" $3; print "ROOM=" $4; print "WORKTIME=" $5 }'


Если запустить скрипт сейчас, то он выведет следующее:

LOGIN=verb666
FULLNAME=Misha Verbitsky
PHONE=+415314499922
ROOM=42
WORKTIME=11:00-16:00


Т.е. уже похоже на присваивание значений переменным bash, но есть проблема. Если мы сейчас скормим вывод awk eval'у, то получим ошибку, например такую:

./awk2vars01: line 8: Verbitsky: command not found

А если бы и не получили, то в переменных могла бы оказаться всякая ерунда, строки необходимо экранировать кавычками.

awk print и вывод кавычки


Кавычки для оператора print awk являются служебными символами, в двойные кавычки берутся строковые литералы, т.е. те строки, которые нужно вывести без изменений, как например, "LOGIN=" в коде выше, а в одинарные - вся программа awk. Экранирование (\" или \') в операторе print приведет к ошибке.

Решение - завести внутреннюю переменную awk, содержащую кавычку, и печатать ее в нужном месте:

echo "$TMPSTRING"|sed -e 's~'\''~~g'|awk -F "," '{print "LOGIN=" sq $1 sq; 
    print "FULLNAME=" sq $2 sq; print "PHONE=" sq $3 sq; print"ROOM=" sq $4 sq;
    print "WORKTIME=" sq $5 sq}' sq="'"



Поскольку данные строки далее будут переданы в eval и обработаны как команды оболочки, то необходимо позаботиться о безопасности, и использовать только одинарные кавычки, а также удалять одинарные кавычки из входных строк, при передаче их awk:

Об опасности использования eval в bash-скриптах. Копия

Вывод:

LOGIN='verb666'
FULLNAME='Misha Verbitsky'
PHONE='+415314499922'
ROOM='42'


Теперь можно обернуть все это в eval, чтобы раскидать результат работы awk по переменным.

eval $(echo "$TMPSTRING"|sed -e 's~'\''~~g'|awk -F "," '{print "LOGIN=" sq $1 sq; 
    print "FULLNAME=" sq $2 sq; print "PHONE=" sq $3 sq;
    print"ROOM=" sq $4 sq;
    print "WORKTIME=" sq $5 sq}' sq="'")


В демо-скрипте я просто вывожу данные на консоль, в реальном скрипте, что понятно, можно делать обработку данных в переменных bash.

echo "Login: $LOGIN"
echo "Full name: $FULLNAME"
echo "Phone: $PHONE"
echo "Room: $ROOM"
echo "Work time: $WORKTIME"


Вывод:

Login: verb666
Full name: Misha Verbitsky
Phone: +415314499922
Room: 42
Work time: 11:00-16:00
...


Скрипты полностью можно посмотреть на GitHub

Немного об оптимизации )

Это репост с сайта http://tolik-punkoff.com
Оригинал: http://tolik-punkoff.com/2020/01/21/zapisat-vyvod-awk-v-neskolko-peremennyh-bash/

Tags: , ,
Back January 22nd, 2020 Forward