awk жалуется на неоконченную строку в команде из объединенных строк - PullRequest
2 голосов
/ 31 мая 2019

Так что фон в том, что я использую команду date внутри awk. Эта команда имеет отличающиеся флаги в Linux / GNU и OSX. Я храню правильную команду с флагами в переменной $date, чтобы обойти это. Следующая команда awk (которая основана на конкатенации строк) завершается неудачно:

awk '{
    cmd = "'$date'" substr( $1, 1, length($1) - 3 ) " +\"%Y-%m-%d %H:%M\""
    if ( (cmd | getline dd) > 0 ) {
        $1 = dd
    }
    close(cmd)
    print
}'

с ошибкой:

awk: non-terminated string date... at source line 2
 context is
         >>>  <<<
awk: giving up
 source line number 3

При замене awk на echo команда выводит корректно:

{
    cmd = "date -r " substr( $1, 1, length($1) - 3 ) " +\"%Y-%m-%d %H:%M\""
    if ( (cmd | getline dd) > 0 ) {
        $1 = dd
    }
    close(cmd)
    print
}

Когда указанный выше скрипт напрямую помещается в awk, он также правильно анализирует даты (он принимает первый аргумент из каждой строки стандартного ввода в качестве метки времени, вырезает микросекунды и преобразует дату в читаемый человеком формат).

$date переменная заполняется следующим образом:

date="date -d @"
date -d @1550000000 &>/dev/null
if [ $? -eq 1 ]; then
    date="date -r "
fi

Ответы [ 2 ]

1 голос
/ 31 мая 2019

Другой ответ, который помог мне разгадать тайну, заключается в том, чтобы настроить метод вызова awk и обойти вопрос сценариев оболочки, заключающийся в том, чтобы обработать awk таким способом.

Думаю, я решил проблему с синтаксисом сценария оболочки. Настройка:

args.sh:

#!/bin/bash

# copypasta code that shoves $1, $2... into 0-indexed bash array and prints it out.
# store arguments in a special array
args=("$@")
# get number of elements
ELEMENTS=${#args[@]}

# echo each element in array
# for loop
for (( i=0;i<$ELEMENTS;i++)); do
    echo ARGS[${i}]: ${args[${i}]}
done

test.sh:

date="date -r "
./args.sh '{
    cmd = "'$date'" substr( $1, 1, length($1) - 3 ) " +\"%Y-%m-%d %H:%M\""
    if ( (cmd | getline dd) > 0 ) {
        $1 = dd
    }
    close(cmd)
    print
}'

Исполнение:

❯ ./args.sh one two three                                                                                                                                                                                                                                                                  
ARGS[0]: one
ARGS[1]: two
ARGS[2]: three

❯ bash test.sh          
ARGS[0]: { cmd = "date
ARGS[1]: -r
ARGS[2]: " substr( $1, 1, length($1) - 3 ) " +\"%Y-%m-%d %H:%M\"" if ( (cmd | getline dd) > 0 ) { $1 = dd } close(cmd) print }

Объяснение: пробелы в вашей наивно расширенной переменной оболочки без двойных кавычек приводят к тому, что тест, использующий echo, не выявляет действительную коренную проблему получения awk 3 аргументов вместо 1 аргумента, как ожидалось. Первым аргументом является неправильная неполная программа awk.

Вот мое исправление: я добавил двойные кавычки. Команда shell теперь выглядит довольно мрачно, с большим количеством цитирования.

❯ cat test.sh     
date="date -r "
./args.sh '{
    cmd = "'"$date"'" substr( $1, 1, length($1) - 3 ) " +\"%Y-%m-%d %H:%M\""
    if ( (cmd | getline dd) > 0 ) {
        $1 = dd
    }
    close(cmd)
    print
}'
❯ bash test.sh   
ARGS[0]: { cmd = "date -r " substr( $1, 1, length($1) - 3 ) " +\"%Y-%m-%d %H:%M\"" if ( (cmd | getline dd) > 0 ) { $1 = dd } close(cmd) print }

Я не буду комментировать использование awk, потому что я не знаю, как использовать awk.

Этот тип кода будет довольно хрупким, но, по крайней мере, у нас пока нет больших стеков обратной косой черты. Кто-нибудь писал в последнее время?

1 голос
/ 31 мая 2019

Вы всегда должны использовать синтаксис -v name=value для передачи переменных оболочки в awk.

Так в вашем случае:

dt="date -r"

awk -v dt="$dt" '{
   cmd = dt substr( $1, 1, length($1) - 3 ) " +\"%Y-%m-%d %H:%M\""
   if ( (cmd | getline dd) > 0 ) {
       $1 = dd
   }
   close(cmd)
   print
}'

Подробнее: Как использовать переменные оболочки в скриптах awk?

Также обратите внимание на полезный комментарий Эда ниже, согласно которому индекс awk начинается с 1 вместо 0 в других языках, таких как C/C++.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...