Аргумент командной строки в awk

sed 's/ [^ ]\{1,4\}/& /' <in >out

>1A    THIS ISATEST

Будет работать, если вставить < пробел> после самого длинного совпадения первого вхождения последовательности от 1 до 4 непробельных символов, следующих сразу за пробелом. Это означает, что если строка начинается с пробелов, это повлияет на первую последовательность без пробелов (что, возможно, является правильным поведением) , или же, если второй столбец, разделенный пробелами, состоит из четырех или менее символов, он добавит дополнительное пространство к этому столбцу (что, возможно, является неправильным поведением) .

Ни в коем случае он не заменяет пробел на каждый четвертый непробельный символ во втором столбце, хотя и преобразует входные данные примера в выходные данные примера.

6
12.10.2018, 12:30
4 ответа

Как уже указывалось, в секции BEGIN не читаются никакие входные данные. Вы можете заставить свой код выполняться, как ожидалось,если вы проверите первую строку ввода и укажите номер на стандартном вводе:

echo 10 | awk 'NR==1{
num=$1;
if (num%2==0)
printf "%d is Even number.\n",num;
else printf "%d is odd Number.\n",num
}'
10 is Even number.
0
27.01.2020, 20:20

Аргументы, указанные в конце командной строки для awk, обычно воспринимаются как имена файлов, из которых скрипт awkбудет читать. Чтобы установить переменную в командной строке, используйте -v variable=value, например.

awk -v num=10 -f script.awk

Это позволит вам использовать numв качестве переменной в вашем скрипте. В приведенном выше примере начальное значение переменной будет равно 10.

Вы также можете прочитать переменные среды, используя ENVIRON["variable"]в своем скрипте (для некоторой переменной среды с именем variable), или просмотреть аргументы командной строки с помощью ARGV[n], где n— некоторое положительное целое число.


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

Число в вашем коде интерпретируется как ноль, поскольку это пустая переменная, используемая в арифметическом контексте.

22
27.01.2020, 20:20

$1не является первым аргументом командной строки, а первым полем после того, как строка была разделена с помощью FS(, и это будет пустая строка в BEGIN, так как ни одна строка еще не была разделена ).

Аргументы командной строки находятся в массивеARGV:

$ awk 'BEGIN { for(i = 1; i < ARGC; i++) print ARGV[i] }' 1st 2nd 3rd
1st
2nd
3rd

ARGV[0]всегда имя интерпретатора(awkили gawkи т. д. ).

Чтобы позволить awkигнорировать аргумент командной строки и не пытаться открыть его позже как файл, вы должны удалить его или установить в качестве пустой строки :, например. ARGV[1]="".

В качестве примечания: любой аргумент в форме var=valueтакже будет интерпретироваться awkкак присвоение переменной и будет оцениваться после того, как аргументы файла, предшествующие ему, будут обработаны. обработано:

$ echo yes > file
$ awk '{ gsub(/e/, var); print }' var=1 file var=2 file var=3 file
y1s
y2s
y3s

Чтобы использовать фактическое имя файла в форме key=valс awk, вы должны передать его как относительный или абсолютный путь, например.awk '{...}'./key=val.

16
27.01.2020, 20:20

Обычный Awk не имеет проблем с обработкой аргументов командной строки, как любая другая программа, подобная C -, не прибегая к какому-либо специфическому GNUgawk-поведению, каналам или перенаправлениям(<)или-v(присваиванию переменных ). ] вариант.

Обработка входных аргументов,ARGC(аргумент счетчик , целое число )иARGV(аргумент вектор , другое слово для «списка» )подробно описаны в руководстве .

Mosvy проделал большую работу, объяснив предысторию и резюмируя, что нужно сделать для разбора ARGV. Вот ваша первоначальная цель, реализованная в виде отдельного сценария оболочки, протестированного как на macOS, так и на GNU/Linux.

simple_if.awk

#!/usr/bin/awk -f
##
##  simple_if - tell user if a number given as an argument is even or odd
##
##  Example:   ./simple_if.awk 11
##
BEGIN {
    num = ARGV[1];

    # if you expect to arguments AND read from one or more input files, you need
    # to remove the arguments from ARGV so Awk doesn't attempt to open them as
    # files (causing an error)
    #ARGV[1] = "";

    if (num % 2 == 0) {
        printf "%d is an even number.\n", num;
    } else {
        printf "%d is an odd number.\n", num;
    }
}

Создайте сценарий Awk, подобный этому , исполняемый с помощью chmod a+x scriptname.awk, поместите его в свой $PATH, и он сможет работать так же, как любой другой сценарий Bash, Python, Perl, программа C и т. д.

Если awkсуществует в каком-то другом месте вашей системы, соответствующим образом обновите строку #!; может быть невозможно использовать /usr/bin/env, потому чтоawkдолжен иметь опцию -fдля запуска вашего скрипта, и… это сложно .

Расширение .awkвовсе не обязательно , но оно может помочь вашему редактору включить правильную подсветку синтаксиса. Оставьте его выключенным, и никому даже не нужно будет знать, что это скрипт Awk.


Вот более полный пример, который делает что-то полезное и имеет разумную обработку ошибок -:

simple_stats.awk

#!/usr/bin/awk -f
##
##  simple_stats - do simple 1-variable statistics (min/max/sum/average) on
##                 the first column of its input file(s)
##
##  examples:     ./simple_stats min numbers.txt
##                ./simple_stats all numbers.txt    # all stats
##                ./simple_stats sum <(du MyFiles)  # Bash proc. substitution
##
##                 # specify '-' as the filename when reading from stdin
##                 seq 1 100 |./simple_stats avg -
##
BEGIN {
    # expect stats operation as the first argument
    op = ARGV[1]

    # unset this array index so Awk doesn't try opening it as a file later
    # ref: https://www.gnu.org/software/gawk/manual/html_node/ARGC-and-ARGV.html
    ARGV[1] = ""  

    # if you wanted to process multiple command line arguments here, you could
    # loop over ARGV, using something like
    # for (i=0; i<ARGC; i++) { if (ARGV[i] == "...") {... } }

    if (op !~ /^(min|max|sum|avg|all)$/) {
        print "ERROR: Expected one of min/max/sum/avg/all." >"/dev/stderr"
        # 'exit' in BEGIN will always run the EXIT block, if one exists
        # see https://www.gnu.org/software/gawk/manual/html_node/Assert-Function.html
        _assert_exit = 1
        exit 1
    }

    # ordinarily Awk reads stdin without specifying; here, '-' seems necessary
    if (ARGV[2] == "") {
        print "ERROR: Need an input file (or '-' for stdin)." >"/dev/stderr"
        _assert_exit = 1
        exit 1
    }
}

# 'min' needs an initial value so take the first record
NR == 1 { min = $1 }

# for every input line (including the first)...
{
    sum += $1
    if ($1 > max) max = $1
    if ($1 < min) min = $1
}

END {
    if (_assert_exit) exit 1;  # if 'exit' was pending from BEGIN block

    if (op == "min" || op == "all")
        printf "The minimum is: %15d\n", min
    if (op == "max" || op == "all")
        printf "The maximum is: %15d\n", max
    if (op == "sum" || op == "all")
        printf "The sum is:     %15d\n", sum
    if (op == "avg" || op == "all")
        printf "The average is: %15.2f\n", sum/NR
}
1
12.02.2020, 09:39

Теги

Похожие вопросы