Я новичок в awk и искал возможность настроить какой-то сценарий bash на работе, который взаимодействует с утилитой awk для анализа вывода некоторых системных файлов. Я внес свои изменения, основываясь на своем понимании, а затем возобладал здравый смысл, и поэтому я подумал, что напишу простую тестовую программу, чтобы опробовать тот же логический шаблон. Но, к моему разочарованию, тестовая программа не сработала должным образом. Я воспроизвожу ниже сценарий bash и сценарий утилиты awk, который я закодировал, вместе с ошибкой, которую я получаю. Цените свои мысли.
bash script
-----------
#!/bin/bash
string=$'a\nb\nc\nd\ne'
echo "$string"
awk -v input=${string} -f post.awk < file_input.txt > file_output.txt
awk script
----------
#!/bin/gawk
BEGIN {
getline tmp
print tmp > $3
}
END{
print $1 > $3
}
В сценарии awk я пытаюсь прочитать одну строку "Only one line" внутри file_input.txt и записать ее в file_output.txt внутри блока BEGIN. Внутри блока END я пытаюсь записать строку, переданную в командной строке скрипту awk, в file_output.txt.
Я получаю следующий вывод при запуске скрипта bash:
а
б
с
г
awk: cmd. line:1: fatal: cannot open file 'c' for reading (No such file or directory)
Очевидно, я не понимаю, как awk обрабатывает аргументы командной строки на основе ошибки. Я предполагал, что в строке
awk -v input=${string} -f post.awk < file_input.txt > file_output.txt
$1 would be input
$2 would be file_input.txt
$3 would be file_output.txt
Может ли кто-нибудь указать, где я ошибся в своих предположениях?
ТИА
В Awk $1, $2 не относятся к аргументам командной строки. Почитайте об этом. Во-вторых, перенаправления в любом случае не являются аргументами команды! Если вы вызываете сценарий оболочки или функцию, такую как command < file1 > file2, не будет $1 и $2, удерживающих file1 и file2. Вместо этого стандартный ввод перенаправляется с file1, а стандартный вывод перенаправляется на file2. У command нет аргументов. Но в любом случае помните, что $1 и $2 в Awk не относятся к аргументам. В Awk есть ARGC счетчик и ARGV[] ассоциативный массив для доступа к командной строке.
В awk$1 — это содержимое первого поля текущей строки.
пожалуйста, обновите вопрос с (правильным) ожидаемым результатом
Вам не нужны отдельные блоки BEGIN и END, и вы не должны использовать getline для этого , весь скрипт должен быть {print; exit} END{print input} или {print; print input; exit} или подобным, в зависимости от ваших неустановленных требований для обработки пустого файла. отредактируйте свой вопрос, чтобы показать ожидаемый результат, когда входной файл пуст, чтобы мы могли вам помочь.
Как указывает тег bash , который вы использовали: «Скрипты оболочки с синтаксисом или другими ошибками, пожалуйста, проверьте их на shellcheck.net, прежде чем публиковать их здесь». Этот инструмент укажет на некоторые проблемы вашего скрипта.





В вашем коде много ошибок:
Вы забываете поставить кавычки ${string}, что приводит к запутанному поведению, когда awk хочет прочитать файл c. Из-за неправильного цитирования вы фактически пытаетесь выполнить:
$ awk -v input=a b c d -f post.awk < file_input.txt > file_output.txt
Здесь вы устанавливаете переменную input=a и пытаетесь прочитать 3 файла (b, c и d). Файл file_input.txt не влияет на скрипт awk, если только вы активно не обрабатываете /dev/stdin в post.awk.
Вы делаете ошибку и считаете, что $n в коде awk представляет _n_th аргумент, переданный awk. Это неправда. В awk $n представляет n_th поле текущей входной записи.
В блоке BEGIN не определена входная запись $0. Только когда определена входная запись, определяются поля ($i, i>0). С другой стороны, блок END знает последнюю входную запись, прочитанную из входного файла.
Вы можете определить входную запись в блоке BEGIN, используя getline как есть, но не getline var, поскольку это не определяет $0.
Итак, как мы можем заставить это работать сейчас.
Если вы просто полагаетесь на простой bash, он будет работать так, как вы хотите. То есть пусть bash определяет с помощью перенаправления, что такое /dev/stdin и /dev/stdout используемой команды. Пример:
$ binary < f1 > f2
Здесь исполняемый файл binary выполняется, когда /dev/stdin указывает на f1, а /dev/stdout указывает на f2.
Таким образом, вы можете сделать то же самое и написать свою программу awk, чтобы просто принять значения по умолчанию /dev/stdin и /dev/stdout.
# post.awk
BEGIN { getline tmp; print tmp }
END { print input }
и выполняя это как:
$ awk -v input = "${string}" -f post.awk file_input.txt > file_output.txt
должен сделать трюк.
Можете ли вы опубликовать точный набор входных данных для вашего сценария bash и сценария awk, а также точный ожидаемый желаемый результат. На данный момент неясно