Если вы не привязаны к 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
Если вы всегда будете использовать $1
в качестве ключа, а оставшуюся часть строки (из$2
)в качестве значения, вы можете использовать index
, чтобы найти, где они находятся в$0
:
index
, чтобы получить местоположение $1
в $2
$1
, чтобы получить подстроку $0
, где первая позиция, где $2
может быть (для случаев, когда $1
может содержать копию$2
)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|
В 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]);
С 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...;>