Обновление определенного поля с помощью sed - PullRequest
0 голосов
/ 10 января 2019

Я пытаюсь обновить определенное поле в определенной строке с помощью команды sed в Bourne Shell.

Допустим, у меня есть файл TopScorer.txt

Player:Games:Goals:Assists
Salah:9:9:3
Kane:10:8:4

И мне нужно обновить 3-ю колонку (голы) игрока, я пробовал эту команду, и она работает, если только у игр и целей не совпадает значение, после которого обновляется первая

player="Salah"
NewGoals="10"
OldGoals=$(awk -F':' '$1=="'$player'"' TopScorer.txt | cut -d':' -f3)
sed -i '/^'$player'/ s/'$OldGoals'/'$NewGoals'/' TopScorer.txt

Output> Salah:10:9:3 instead of Salah:9:10:3

Есть ли решение? Следует ли использовать разделители и $3==... для указания этого поля? Я также попробовал параметр / 2 для второго появления, но в моем случае он не очень удобен.

Ответы [ 5 ]

0 голосов
/ 10 января 2019

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

(player=Salah;newGoals=10;sed -i "/^$name/s/[^:]*/$newGoals/3" /tmp/file)

Используйте вспомогательную оболочку, чтобы не загрязнять текущую оболочку (...). Используйте sed и сопоставление с образцом, чтобы сопоставить первое поле каждой записи с переменной player и заменить третье поле сопоставляемой записи содержимым newGoals.

P.S. Если переменные требуются в дальнейших процессах, то вспомогательная оболочка не нужна, то есть удалите ( и )

0 голосов
/ 10 января 2019

Вы можете попробовать это с Perl

$ player="Salah"
$ NewGoals="10"
$ perl -F: -lane "\$F[2]=$NewGoals  if ( \$F[0] eq $player ) ; print join(':',@F) " TopScorer.txt
Player:Games:Goals:Assists
Salah:9:10:3
Kane:10:8:4
$

или экспортируйте их и вызывайте Perl с одинарной кавычкой в ​​одинарных кавычках

$ export NewGoals="10"
$ export player="Salah"
$  perl -F: -lane '$F[2]=$ENV{NewGoals} if $F[0] eq $ENV{player} ; print join(":",@F) ' TopScorer.txt
Player:Games:Goals:Assists
Salah:9:10:3
Kane:10:8:4
$

Обратите внимание, что в Perl есть ключ -i, и вы можете выполнить замену на месте, поэтому

$ perl -i.bak -F: -lane '$F[2]=$ENV{NewGoals} if $F[0] eq $ENV{player} ; print join(":",@F) ' TopScorer.txt
$ cat TopScorer.txt
Player:Games:Goals:Assists
Salah:9:10:3
Kane:10:8:4
$
0 голосов
/ 10 января 2019

Вы можете сделать это только с awk, а не с sed. Также обратите внимание, что awk имеет внутренний синтаксис для импорта переменных из оболочки. Таким образом, ваш код просто становится

awk -F: -v pl="$player" -v goals="$NewGoals" 
    'BEGIN { OFS = FS } $1 == pl { $3= goals }1' TopScorer.txt

-F: устанавливает ограничитель ввода как :, а часть, включающая -v, импортирует переменные оболочки в контекст awk. BEGIN { OFS = FS } устанавливает разделитель выходного поля так же, как ввод. Затем мы сопоставляем импортированные переменные и обновляем $3 до необходимого значения.

Чтобы внести изменения на месте, используйте временный файл

awk -F: -v pl="$player" -v goals="$NewGoals" 
   'BEGIN { OFS = FS } $1 == pl { $3= goals }1' TopScorer.txt > tmpfile && mv tmpfile TopScorer.txt
0 голосов
/ 10 января 2019

Не могли бы вы попробовать один раз. Преимущество такого подхода в том, что я не являюсь жестким полем для целей. Эта программа будет искать поле заголовка там, где присутствует цель (например, -> 4-е или 5-е поле), оно будет изменяться только для этого конкретного столбца.

1-е решение: Если вам нужно внести изменения во все вхождения имени игрока, используйте следующее.

NewGoals=10
awk -v newgoals="$NewGoals" 'BEGIN{FS=OFS=":"} FNR==1{for(i=1;i<=NF;i++){if($i=="Goals"){field=i}}} FNR>1{if($1=="Salah"){$field=newgoals}} 1' Input_file

2-е решение: Если вы хотите изменить значение цели конкретного игрока только на конкретную строку, то попробуйте выполнить следующее.

NewGoals=10
awk -v newgoals="$NewGoals" 'BEGIN{FS=OFS=":"} FNR==1{for(i=1;i<=NF;i++){if($i=="Goals"){field=i}}} FNR>1{if($1=="Salah" && FNR==2){$field=newgoals}} 1' Input_file

Выше будут вноситься изменения только для строки 2, вы можете изменить ее, изменив FNR==2 во втором условии, где FNR ссылается на номер строки в awk. Если вы хотите сохранить вывод в сам файл Input_file, вы можете добавить > temp_file && mv temp_file Input_file к вышеуказанным кодам.

0 голосов
/ 10 января 2019

Это будет работать.

В первой части sed я пытаюсь сопоставить полную строку, в которой указан игрок, и сохраняю все поля, которые хочу сохранить, используя \ (.

Вторая часть, я перестраиваю строку с некоторыми константами и значением \ 1 и значением \ 2

player="Salah"
NewGoals="10"
sed "s/^$player:\([^:]*\):[^:]*:\([^:]*\)\$/$player:\1:$NewGoals:\2/"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...