2012-05-23 1 views
2

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

awk '$3~/hi/' < test.txt # print all lines where the third field matches the pattern "hi" 

или

awk '$2>=2' < test.txt # print all lines where the second field is greater or equal to 2 

Как новичок, который узнав о силе юниксовских, я абсолютно очарован об этом. Теперь мне интересно, есть ли простой способ выполнять подстановки регулярных выражений только для некоторых произвольных полей, которые вы указали? Например, я хочу сделать замену регулярных выражений только в третьем поле. мой текущий метод - это «вырезать» поле, которое я хочу, и выполнять подстановку с помощью Perl или sed, которые затем «вставляют» в исходный файл. Но мне интересно, есть ли более эффективный способ достичь этого.

Благодаря

ответ

4

Поскольку вы помечено этот вопрос с «Perl» (в дополнение к «SED», «AWK», «Unix» и «командной строки»), я предполагаю, что вы заинтересованы в ответах, которые включают любой из вышеперечисленных инструментов.

Perl имеет автоматическое разделение переключатель командной строки (-a):

perl -lane 'print if $F[2] =~ /some pattern/' filename 

... или ...

perl -lane 'print if $F[1] >= 42' filename 

-a вызывает автоматическое разделение в @F массив. -n заставляет Perl перебирать строки файла, который вы его кормите. Остальное - программирование. ;)

Теперь для замены:

perl -i.bak -lane '$F[2] =~ s/match/subst/; print join q/ /, @F' filename 

Или немного короче, используя -p переключатель, который говорит Perl печатать каждую строку, как он появляется в $_. Это означает, что если вы изменяете @F, вы должны скопировать его обратно в $_:

perl -i.bak -pale '$F[2] =~ s/match/subst/ && $_="@F"' filename 
3

Это может работать для вас:

echo -e 'Fred barney Wilma\nfoo bar baz' | 
awk '$2 == "barney"{sub(/b/,"B",$2)};1' 
Fred Barney Wilma 
foo bar baz 

Вы можете использовать sub, gsub команды или это этот случай :

echo -e 'Fred barney Wilma\nfoo bar baz'| 
awk '$2 == "barney"{$2="Barney"};1' 
Fred Barney Wilma 
foo bar baz 

Просто замените второе поле полностью.

N.B. 1 в конце строки является сокращением для {print}.

1

Рассмотрим простой пример:

awk -F "," '{ OFS=","; sub ("1", "x", $3); print $0 }' file.txt > newfile.txt

newfile.txt теперь будет содержать:

1,2,3,4,5,6,7 
8,9,x0,11,12,13,14 
15,16,x7,18,19,20,21 

Здесь 1 был заменен x в третьем столбце $3.
-F "," устанавливает разделитель входного файла. OFS="," добавляет запятую к выходу.

Если вы хотите сделать замену глобально, рассмотрите возможность использования gsub вместо sub.

НТН

+1

Я думаю, что было бы лучше, чтобы установить значение 'OFS' раз и перед чтением входного файла в' BEGIN' блока, как 'AWK -F«»«BEGIN {OFS = „“ } {sub ...} '' – Birei