/usr/bin/awk
в Solaris сильно ограничен в поддержке различных функций. В частности, функция gsub()
не реализована. Это объясняется в руководстве для awk
на Solaris .
Для этого вы должны использовать/usr/xpg4/bin/awk
(или nawk
, "новый awk
" ).
В вашем коде также не указан разделитель полей для awk
, поэтому $3
никогда ничего не будет содержать, если в ваших данных не окажется достаточно пробелов, чтобы случайно создать третье поле, разделенное пробелами. Точно так же вы не указываете разделитель выходных полей, поэтому любые измененные строки будут иметь свои поля, разделенные пробелами.
Вместо:
/usr/xpg4/bin/awk -F '|' 'BEGIN { OFS=FS } { gsub(",", "|", $3); print }' file
Чтобы всегда получать /usr/xpg4/bin/awk
в качестве awk
по умолчанию в Solaris, используйте PATH="$(/usr/xpg4/bin/getconf PATH):$PATH"
в файле запуска вашей оболочки.
Чтобы не перегружать регулярное выражение, поскольку список исключений может быть более 200, мы сначала генерируем код sed, используя файл списка исключений, и применяем этот сгенерированный код к входным данным.
GNU-сед
sed -e '
1i\
s/dank/\\n/g
h;s:[\&/]:\\&:g
x;s/dank/\n/g
s:[][^$\/.*]:\\&:g
s/\n/\\n/g;G
s:\n:/:;s:.*:s/&/g:
$a\
s/\\n/MONK/g
' excludes.txt | sed -f - file
Выход:-
xdankine reMONKus
dankzwd
MONKe MONKbe
testMONK
Подтверждение концепции:-
nudankip
, как указано ниже, а также для всех строк в списке исключений. s/nu\nip/nudankip/g
Если у вас есть только одно вхождение dank
в строке, как в вашем примере, вы можете использовать инвертированные адреса:
sed -E '/dankine|dankzwd|nudankip|dankphys|danko\.mod/!s/dank/monk/'
Если в строке может быть несколько вхождений, вы можете использовать символ, который не может быть частью файла, например. грамм. #
, изменить все dank
на #
, вернуться к списку слов и изменить #
на monk
для остальных:
sed 's/dank/#/g;s/#ine/dankine/g;s/#zwd/dankzwd/g;s/nu#ip/nudankip/g;s/#phys/dankphys/g;s/#o\.mod/danko.mod/g;s/#/monk/g'
(Если может встречаться любой символ, используйте вместо него новую строку)
Обновление :Новое требование для чтения списка исключений из файла
Запишите свой черный список в файлexclusion.list
с символом новой строки в конце(скрипт будет использовать это, чтобы определить, где заканчивается первый файл):
sed -e '1,/^$/{H;d;}' -e 'G;s/\n/&&/;:loop' -e 's/\(.*da\)\(nk.*\)\(.*\n\1\2\n\)/\1#\2\3/;tloop' -e 's/\n.*//;s/dank/monk/g;s/da#nk/dank/g' exclusion.list file
или,как многострочный, возможно, легче читать
sed '1,/^$/{H;d;}
G
s/\n/&&/
:loop
s/\(.*da\)\(nk.*\)\(.*\n\1\2\n\)/\1#\2\3/
tloop
s/\n.*//
s/dank/monk/g
s/da#nk/dank/g' exclusion.list file
Во всяком случае, это может быть легче написать, чем прочитать. Концепция
dank
в файле, который появляется в списке, на da#nk
, чтобы предотвратить его замену позже dank
на monk
и, наконец, удалите #
из da#nk
с. Добавление l
после :loop
иллюстрирует принцип работы.
Спасибо Стефану за намек на проблему dankfoodank
, которая здесь решается. Однако требование для случая dankdank
остается неясным. Должно ли это быть dankmonk
, потому что только dank
из dankda
защищено, или оно должно оставаться dankdank
, потому что da
второго dank
защищено как часть dankda
или это выходит за рамки?
Использование любого awk в любой оболочке на каждом компьютере Unix и использование литеральных строковых операций, поэтому нам не нужны метасимволы регулярных выражений или обратных ссылок во входных данных или списке исключений:
$ cat tst.awk
NR==FNR {
mask[$0] = RS NR RS
next
}
{
delete changed
for (exception in mask) {
while ( s=index($0,exception) ) {
$0 = substr($0,1,s-1) mask[exception] substr($0,s+length(exception))
changed[exception]
}
}
gsub(/dank/,"monk")
for (exception in changed) {
while ( s=index($0,mask[exception]) ) {
$0 = substr($0,1,s-1) exception substr($0,s+length(mask[exception]))
}
}
print
}
$ awk -f tst.awk exceptions file
xdankine remonkus
dankzwd
monke monkbe
testmonk
Вышеизложенное предполагает, что у вас нет исключений, которые являются подстроками других исключений, таких как dankfoo
и dankdankfoo
, поскольку вы не показываете такие случаи в примере в вашем вопросе. Если вы это сделаете, убедитесь, что файл исключений отсортирован таким образом, что более длинные суперстроки идут перед более короткими подстроками и повторяются в том порядке, в котором они были введены, чтобы вы не заменяли xdankdankfooy
на xdank<replacement>y
вместо x<replacement>y
, когда маскирование исключений в первом цикле.
С помощью perl
можно сделать:
perl -pe '
BEGIN{
chomp (@excl = <STDIN>);
$re = "(". join( "|", map {qr{\Q$_\E}} @excl). ")|dank"
}
s{$re}{$1//"monk"}ge' input < exclusion.list
Это создает регулярное выражение, такое как:
(dankine|dankzwd|nudankip|dankphys|danko\.mod)|dank
И мы заменяем любое его вхождение либо на$1
(так что было сопоставлено, то есть по сути ничего не делая )если $1
установлено (одно из исключений совпало )или monk
в противном случае(dank
вместо ).
Обратите внимание, что если исключения включают как dankzwd
, так и zwddank
, это все равно превратит dankzwddank
в dankzwdmonk
, поскольку сначала заменяет dankzwd
на dankzwd
($1
), а затем остается только dank
для его заменить.
Подход к адресации, заключающийся в том, чтобы записывать все места, где происходит какое-либо исключение в строке маски, а затем, когда дело доходит до замены dank
, выполнять замену только там, где маска говорит, что все в порядке.
perl -spe '
BEGIN {
chomp (@excl = <STDIN>);
$word_len = length $word;
}
my $len = length;
my $mask = "-" x $len;
my $i;
for my $e (@excl) {
my $e_len = length $e;
my $hide = "#" x $e_len;
for (my $o = 0;
$o < $len && ($i = index($_, $e, $o)) >= 0;
$o = $i + 1) {
substr($mask, $i, $e_len) = $hide;
}
}
s{dank}{substr($mask, pos, $word_len) =~ /-/ ? $repl : $&}ge
' -- -word=dank -repl=monk input < exclusion.list
Так, например, если входная строка содержит:
dodankdankdankoodankdodank
и исключения имеют :dankdank
, dankdo
маска будет построена постепенно из
--------------------------
--########---------------- # first dankdank
--############------------ # second dankdank
--############--######---- # first and only dankdo
dodankdankdankoodankdodank
^^^^
Тогда остается только dank
в конце, на который не влияют исключения.