sed 's/ [^ ]\{1,4\}/& /' <in >out
>1A THIS ISATEST
Будет работать, если вставить < пробел> после самого длинного совпадения первого вхождения последовательности от 1 до 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.
Аргументы, указанные в конце командной строки для awk
, обычно воспринимаются как имена файлов, из которых скрипт awk
будет читать. Чтобы установить переменную в командной строке, используйте -v variable=value
, например.
awk -v num=10 -f script.awk
Это позволит вам использовать num
в качестве переменной в вашем скрипте. В приведенном выше примере начальное значение переменной будет равно 10.
Вы также можете прочитать переменные среды, используя ENVIRON["variable"]
в своем скрипте (для некоторой переменной среды с именем variable
), или просмотреть аргументы командной строки с помощью ARGV[n]
, где n
— некоторое положительное целое число.
С помощью $1
в awk
вы бы ссылались на значение первого поля в текущей записи, но, поскольку вы используете его в блоке BEGIN
, данные еще не были считаны ни из одного файла.
Число в вашем коде интерпретируется как ноль, поскольку это пустая переменная, используемая в арифметическом контексте.
$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
.
Обычный 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
}