awk '{
for (i=1; i<=NF; i++)
if ($i == "a" && n < 3) {
n++
$i = "Z"
}
print
}' alphabet
Ou "one-liner" -ed
awk '{for (i=1;i<=NF;i++) if ($i=="a" && n++<3) $i="Z"; print}' alphabet
Eu recebi um arquivo alphabet
, em que a
tem várias ocorrências em uma linha.
$ cat alphabet
a b c d e f g
h i j k a a l
m n a p q r a
s t u v w a x
y z a k l q z
onde
$ cat alphabet | grep -o a | wc -l
7
Agora, como posso substituir apenas as três primeiras ocorrências de a
por Z
para que meu arquivo seja semelhante ao seguinte
Z b c d e f g
h i j k Z Z l
m n a p q r a
s t u v w a x
y z a k l q z
Perl para o resgate:
perl -pe '$c++ while $c < 3 && s/a/Z/' alphabet
Aqui, o caminho sed
sed -E ':a;N;$!ba;s#a#Z#;s#a#Z#;s#a#Z#' alphabet
Como o sed normalmente funciona em linhas, qualquer comando para sed funcionará apenas em uma linha por vez. Para poder substituir apenas as 3 primeiras ocorrências, precisamos primeiro tornar o arquivo inteiro uma única seleção na qual faremos nossas 3 substituições. Caso contrário, faremos 3 substituições em cada linha.
:a
cria um rótulo N
acrescenta a próxima linha ao espaço de padrões $!
ignora a última nova linha ba
ramifica para rotular a
Agora selecionamos o arquivo inteiro e estaremos atuando nesse espaço em vez de uma linha de cada vez, fazer 3 substituições de "a" com "Z".
O comando acima só funcionará no GNU sed, mais geral, mas com uma versão um pouco mais feia que deve funcionar no modo não-GNU sed:
sed -e ':a' -e 'N' -e '$!ba' -e 's#a#Z#' -e 's#a#Z#' -e 's#a#Z#' alphabet
EDITAR: Como sugerido nos comentários, adicionando a versão que usa o comando g para primeiro substituir todas as ocorrências de 'a' com 'Z' e então substituir todas as ocorrências de 'Z' depois de 3 com 'a' novamente, o que efetivamente leva a substituir apenas o primeiro 3 ocorrências de 'a'. Desta forma, você pode alterar o último número para refletir o número de substituições que você precisa.
sed -e ':a;N;$!ba;s#a#Z#g;s#Z#a#g4' alphabet
A solução awk
que foi publicada
assume que todas as ocorrências de a
são palavras separadas.
Embora isso seja verdade para os dados exemplo ,
não é especificado como sendo verdadeiro dos dados reais.
A seguinte solução awk
está mais no espírito da solução perl
que foi postada:
awk '{ while (changes < 3 && sub("a", "Z") > 0) changes++; print }' alphabet
Isso substitui as ocorrências ( sub stitutes) de a
por Z
até que o contador changes
atinja 3.
Claro, para realmente mudar o arquivo, você precisará fazer algo como
awk '{while (c < 3 && sub("a","Z")>0) c++; print}' alphabet > t && cp t alphabet && rm t
em que t
é um arquivo temporário.