Когда интерпретируют awk как команду или язык программирования?

Это может быть не так, как правило, как то, что вы действительно хотите, но вот отправную точку:

 sed -n '/SOMETHING/!q;p'

Это говорит: проверьте на наличие совпадения / что-то / . Если линия не совпадает (используя ! , чтобы инвертировать результат теста), затем выйти. В противном случае распечатайте эту строку и продолжайте до следующей строки.

Это не сразу же гибко, чтобы позволить вам делать то, что вы просили, А также другие манипуляции на файл, все в одном COD команда.

0
16.10.2014, 13:39
2 ответа

awk имеет два режима призыва, один с текстом программы в командной строке и другой с программой из файла. Это указано в синопсе страницы человека AWK (этот из Mawk на Ubuntu 12.04):

   mawk  [-W  option] [-F value] [-v var=value] [--] 'program text' [file
   ...]
   mawk [-W option] [-F value]  [-v  var=value]  [-f  program-file]  [--]
   [file ...]

должен вызывать ли первую форму программу или не зависит от определения программы, которую вы хотите использовать. Я бы сказал, обе формы включают в себя программы, в зависимости от первой программы указана как аргумент командной линии. Оба ваших примера должны быть первой формы, так как не включает в себя опцию -F . То, что второй пример имеет многослойный аргумент командной линии, по отношению к этому неактуально.

Это не уникально для awk . например Python по умолчанию интерпретает аргумент командной линии в качестве имени программы, но с опцией позволяет указывать программу в командной линии (т. Е. По умолчанию находятся наоборот вокруг awk ).

Независимо от этого, это связь с использованием труб. Это позаботится о синтаксисе оболочки и ОС, единственное, что ваш скрипт должен делать, это запись на STDOUT, REPS. Читайте из Stdin. Так что да AWK программы могут общаться по трубам.

4
28.01.2020, 02:14
lcomma() { sed '
    $x;$G;/\(.*\),/!H;//!{$!d
};  $!x;$s//\1/;s/^\n//'
}

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

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

Я просто копал свой файл истории и нашел следующее:

lmatch(){ set "USAGE:\
        lmatch /BRE [-(((s|-sub) BRE)|(r|-ref)) REPL [-(f|-flag) FLAG]*]*
"       "${1%"${1#?}"}" "$@"
        eval "${ZSH_VERSION:+emulate sh}"; eval '
        sed "   1x;     \\$3$2!{1!H;\$!d
                };      \\$3$2{x;1!p;\$!d;x
                };      \\$3$2!x;\\$3$2!b'"
        $(      unset h;i=3 p=:-:shfr e='\033[' m=$(($#+1)) f=OPTERR
                [ -t 2 ] && f=$e\2K$e'1;41;17m}\r${h-'$f$e\0m
                f='\${$m?"\"${h-'$f':\t\${$i$e\n}\$1\""}\\c' e=} _o=
                o(){    IFS=\ ;getopts  $p a "$1"       &&
                        [ -n "${a#[?:]}" ]              &&
                        o=${a#-}${OPTARG-${1#-?}}       ||
                        ! eval "o=$f;o=\${o%%*\{$m\}*}"
        };      a(){    case ${a#[!-]}$o in (?|-*) a=;;esac; o=
                        set $* "${3-$2$}{$((i+=!${#a}))${a:+#-?}}"\
                                ${3+$2 "{$((i+=1))$e"} $2
                        IFS=$;  _o=${_o%"${3+$_o} "*}$*\
        };      while   eval "o \"\${$((i+=(OPTIND=1)))}\""
                do      case            ${o#[!$a]}      in
                        (s*|ub)         a s 2 ''        ;;
                        (r*|ef)         a s 2           ;;
                        (f*|lag)        a               ;;
                        (h*|elp)        h= o; break     ;;
                esac;   done;   set -f; printf  "\t%b\n\t" $o $_o
)\"";}

Это на самом деле довольно хорошо. Да, он использует eval , но никогда не передает ему ничего за пределы числовой ссылки на его аргументы. Он создает произвольные сценарии sed для обработки последнего совпадения. Я покажу вам:

printf "%d\" %d' %d\" %d'\n" $(seq 5 5 200) |                               
    tee /dev/fd/2 |                                                         
    lmatch  d^.0     \  #all re's delimit w/ d now                           
        -r '&&&&'    \  #-r or --ref like: '...s//$ref/...'      
        --sub \' sq  \  #-s or --sub like: '...s/$arg1/$arg2/...'
        --flag 4     \  #-f or --flag appended to last -r or -s
        -s\" \\dq    \  #short opts can be '-s $arg1 $arg2' or '-r$arg1'
        -fg             #tacked on so: '...s/"/dq/g...'                     

Это печатает следующее на stderr. Это копия ввода lmatch :

5" 10' 15" 20'
25" 30' 35" 40'
45" 50' 55" 60'
65" 70' 75" 80'
85" 90' 95" 100'
105" 110' 115" 120'
125" 130' 135" 140'
145" 150' 155" 160'
165" 170' 175" 180'
185" 190' 195" 200'

Функция eval ed выполняет итерацию через все ее аргументы один раз. По мере перемещения над ними он соответствующим образом итерирует счетчик в зависимости от контекста для каждого переключателя и пропускает множество аргументов для следующей итерации. С этого момента он делает одну из нескольких вещей на аргумент:

  • Для каждой опции синтаксический анализатор добавляет $ a к $ o . $ a назначается на основе значения $ i , которое увеличивается на число arg для каждого обработанного arg. $ a присваивается одно из двух следующих значений:
    • a = $ ((i + = 1)) - этот параметр назначается, если либо короткая опция не имеет добавленного аргумента, либо опция была длинной.
    • a = $ i # -? - этот параметр назначается, если опция является короткой и к ней присоединен арг .
    • a =\$ {$ a} $ {1: + $ d\$ {$ (($1))\}} - Независимо от первоначального назначения, значение $ a всегда оборачивается фигурными скобками и - в случае -s - иногда $ i увеличивается еще на один и дополнительно ограничивается поле добавляется.

В результате eval никогда не передается последовательности, содержащему неизвестных. На каждый из аргументов командной строки ссылается их числовой номер аргумента - даже разделитель, который извлекается из первого символа первого аргумента и является единственным случаем использования любого символа, который не скрыт. В основном, функция является макрогенератором - она никогда не интерпретирует значения аргументов в каких-либо специальных путях, потому что sed может (и, конечно) легко обрабатывать это при разборе сценария. Вместо этого он просто разумно упорядочивает свои аргументы в работоспособный сценарий.

Вот некоторые отладочные выходные данные функции в работе:

... sed "   1x;\\$2$1!{1!H;\$!d
        };      \\$2$1{x;1!p;\$!d;x
        };      \\$2$1!x;\\$2$1!b
        s$1$1${4}$1
        s$1${6}$1${7}$1${9}
        s$1${10#-?}$1${11}$1${12#-?}
        "
++ sed '        1x;\d^.0d!{1!H;$!d
        };      \d^.0d{x;1!p;$!d;x
        };      \d^.0d!x;\d^.0d!b
        sdd&&&&d
        sd'\''dsqd4
        sd"d\dqdg
        '

И поэтому lmatch можно использовать для простого применения регексов к данным после последнего совпадения в файле. Результат выполнения команды выше:

5" 10' 15" 20'
25" 30' 35" 40'
45" 50' 55" 60'
65" 70' 75" 80'
85" 90' 95" 100'
101010105dq 110' 115dq 120'
125dq 130' 135dq 140sq
145dq 150' 155dq 160'
165dq 170' 175dq 180'
185dq 190' 195dq 200'

..., которая, учитывая подмножество ввода файла, следующего за последним совпадением /^ .0/, применяет следующие замены:

  • sdd & & & & & d -заменяет $ match на себя 4 раз.
  • sd 'dsqd4 - четвертая единичная цитата, следующая за началом строки с момента последнего матча.
  • sd "d\dqd2 - ditto, но для двойных кавычек и глобально.

И поэтому, чтобы продемонстрировать, как можно использовать lmatch для удаления последней запятой в файле:

printf "%d, %d %d, %d\n" $(seq 5 5 100) |
lmatch '/\(.*\),' -r\\1

OUTPUT:

5, 10 15, 20
25, 30 35, 40
45, 50 55, 60
65, 70 75, 80
85, 90 95 100
-121--28715-

Использование стандартного перенаправления будет работать на стандартном выходе:

$ awk -F'"' -v OFS='' '{ for (i=2; i<=NF; i+=2) gsub(",", "", $i) } 1' infile > test.out
$

Это все равно будет выводить ошибки на экран.

Однако, если вы хотите, чтобы ошибки и стандартные исходили в файл, то запустите:

$ awk -F'"' -v OFS='' '{ for (i=2; i<=NF; i+=2) gsub(",", "", $i) } 1' infile 2>&1 > test.out
$

Или вы можете отделить ошибки от стандартного вывода:

awk -F'"' -v OFS='' '{ for (i=2; i<=NF; i+=2) gsub(",", "", $i) } 1' infile 2> errors.out 1 > test.out
-121--175439-

Строго говоря, при вызове awk вы ссылаетесь на интерпретатор, а не на язык. Язык называется AWK .

awk (или mawk , nawk ) - это только утилита, которая будет выполнять программы, написанные на языке программирования AWK .

Как определено POSIX, программа awk является:

программа

Если параметр -f не указан, первым операндом для awk должен быть текст программы awk. Приложение должно предоставить программу операнд как единственный аргумент к неловкости. Если текст не заканчивается на , awk интерпретирует текст так, как если бы он это сделал.

Таким образом, если вы не используете опцию -f , вы можете рассматривать два примера в качестве программы «неловкости».

3
28.01.2020, 02:14

Теги

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