AWK :как узнать, где начинается столбец

Если вы не привязаны к sed, это очень легко сделать вperl:

$ perl -pe 'BEGIN{$k=4};s/Keyword "/$&. ++$k. " - "/e' file 
Keyword "5 - name"
aaa bbb
ccc ddd

Keyword "6 - another name"
eee fff
ggg
hhh iii
4
11.05.2021, 15:38
3 ответа

Если вы всегда будете использовать $1в качестве ключа, а оставшуюся часть строки (из$2)в качестве значения, вы можете использовать index, чтобы найти, где они находятся в$0:

  1. Используйте index, чтобы получить местоположение $1в $2
  2. .
  3. Затем используйте длину $1, чтобы получить подстроку $0, где первая позиция, где $2может быть (для случаев, когда $1может содержать копию$2)
  4. Затем снова используйте index, чтобы получить расположение $2, чтобы мы могли извлечь подстроку, начинающуюся с $2.

Пример:

# foo.awk
function mysplit(array) {
    pos1 = index($0, $1)
    sub1 = substr($0, pos1 + length($1))
    pos2 = index(sub1, $2)
    sub2 = substr(sub1, pos2)
    array[$1] = sub2
}

{mysplit(arr)}

END {
    for (i in arr) {
        printf "[%s]:   |%s|\n", i, arr[i]
    }
}

С вашими примерами:

% echo -n -e " \tFirst \t\t  Second \t Third  \t" | awk -f foo.awk -F " " | sed 's/\t/\\t/g'
[First]:   |Second \t Third  \t|
% echo -n -e " \tFirst \t\t  Second \t Third  \t" | awk -f foo.awk -F "\t" | sed 's/\t/\\t/g'
[ ]:   |First \t\t  Second \t Third  \t|
% echo -n -e " \tFirst \t\t  Second \t Third  \t" | awk -f foo.awk -F "[ \t]+" | sed 's/\t/\\t/g'
[]:   |First \t\t  Second \t Third  \t|
1
28.07.2021, 11:33

В GNU/awk вы можете использовать split()с необязательным аргументом seps, затем перебирать arrayи sepsдля создания массивов startи sizeдля каждого поля, накапливая длину каждое поле и разделитель.

Этот код предназначен для GNU/awk. Функция Offsets ()принимает текстовую строку и шаблон для разделителей полей и возвращает пару массивов, содержащих начальный столбец и длину полей.

$ cat myCols
#! /bin/bash

myCols () {

    local Awk='
BEGIN { cmdDu = "od -A n -t a"; }
#.. Debug the input.
function Debug (tx, Local ) {
    printf ("\nLine %2d: %s\n", NR, tx);
    printf ("%s", tx) | cmdDu; close (cmdDu);
}
#.. Return arrays of column start and length.
function Offsets (col, lth, tx, re, Local, fld, sep, f) {
    delete col; delete lth;
    split (tx, fld, re, sep);
    c = length (sep[0]);
    for (f = 1; f in fld; ++f) {
        col[f] = 1 + c; lth[f] = length (fld[f]);
        c += length (fld[f]) + length (sep[f]);
    }
}
#.. Find fields and show the results.
function Fields (tx, re, Local, col, lth, f) {
    Offsets( col, lth, tx, re);
    for (f = 1; f in col; ++f) {
        printf ("Field %d col %3d lth %3d >%s<\n",
            f, col[f], lth[f], substr (tx, col[f], lth [f]));
    }
}
{ Debug( $0); }
NR == 1 { Fields( $0, ",[[:space:]]*"); }
NR == 2 { Fields( $0, FS); }
'
    awk -f <( printf '%s' "${Awk}" )

}

    {
        echo "Never,   Ever,  Forget,  but maybe,   Forgive"
        echo -n -e " \tFirst \t\t  Second \t Third  \t"
    } | myCols

И проверить:

$./myCols

Line  1: Never,   Ever,  Forget,  but maybe,   Forgive
   N   e   v   e   r  ,  sp  sp  sp   E   v   e   r  ,  sp  sp
   F   o   r   g   e   t  ,  sp  sp   b   u   t  sp   m   a   y
   b   e  ,  sp  sp  sp   F   o   r   g   i   v   e
Field 1 col   1 lth   5 >Never<
Field 2 col  10 lth   4 >Ever<
Field 3 col  17 lth   6 >Forget<
Field 4 col  26 lth   9 >but maybe<
Field 5 col  39 lth   7 >Forgive<

Line  2:    First         Second     Third      
  sp  ht   F   i   r   s   t  sp  ht  ht  sp  sp   S   e   c   o
   n   d  sp  ht  sp   T   h   i   r   d  sp  sp  ht
Field 1 col   3 lth   5 >First<
Field 2 col  13 lth   6 >Second<
Field 3 col  22 lth   5 >Third<
$ 

Если вам нужна точная исходная строка, начинающаяся с (, скажем )в третьем поле, используйте:

if (3 in col) Tail = substr (tx, col[3]);
2
28.07.2021, 11:33

С GNU awk для разделения 4-го аргумента():

$ cat tst.awk
{
    split($0,flds,FS,seps)
    key = flds[1]
    pos = length(seps[0] flds[1] seps[1]) + 1
    val = substr($0,pos)
    printf "key=<%s>\npos=<%s>\nval=<%s>\n\n", key, pos, val
}

$ printf -- ' \tFirst \t\t  Second \t Third  \t\n' | awk -f tst.awk
key=<First>
pos=<13>
val=<Second      Third          >

$ printf -- '-11...22;,;..;33-44...;\n' | awk -F'[^0-9-]+' -f tst.awk
key=<-11>
pos=<7>
val=<22;,;..;33-44...;>
2
28.07.2021, 11:33

Теги

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