awk sed if declaração


9

Estou tentando adicionar 0 ao início, se houver um "." no segundo caractere dessa linha. Eu não conseguia combinar esses dois;

awk '{ print substr( $0, 2, 1 ) }' file.txt 

mostrando o segundo caractere

sed -ie "s/.\{0\}/0/" file.txt

adicionando um zero ao começo.

Deve haver um "se o segundo caractere for um ponto".

arquivo de exemplo:

1.02.2017 23:40:00
10.02.2017 23:40:00

final:

01.02.2017 23:40:00
10.02.2017 23:40:00

Respostas:


12

Podemos usar sedou awkresolver completamente o problema.


Com sed:

$ sed 's/^.\./0&/' file.txt

Quando &ocorrer na parte de substituição do comando de substituição ( s), ela será expandida para a parte da linha de entrada que corresponde à parte padrão do comando.

A expressão regular ^.\.significa " corresponder a todas as linhas que começam com ( ^) um caractere arbitrário ( .) seguido por um ponto literal ( \.) ".

Se a linha for 1.02.2017 23:40:00, o padrão corresponderá e 1.será substituído por 01.no início da linha.


Com awk:

Com base no awkcódigo parcial na pergunta ...

Isso, como indicado, imprimirá o segundo caractere de cada linha de entrada:

$ awk '{ print substr($0, 2, 1) }' file.txt

Podemos usar o fato de substr($0, 2, 1)retornar o segundo caractere e usá-lo como condição:

$ awk 'substr($0, 2, 1) == "." { ... }' file.txt

O que entra { ... }é o código que precede $0, que é o conteúdo da linha atual, com um zero se a condição anterior for verdadeira:

$ awk 'substr($0, 2, 1) == "." { $0 = "0" $0 }' file.txt

Então, precisamos apenas garantir que todas as linhas sejam impressas:

$ awk 'substr($0, 2, 1) == "." { $0 = "0" $0 } { print }' file.txt

substr($0, 2, 1) == "."Obviamente, a condição também pode ser alterada para uma expressão regular (usamos exatamente a mesma expressão que usamos na sedsolução):

$ awk '/^.\./ { $0 = "0" $0 } { print }' file.txt

Algumas pessoas que pensam que "menor é sempre melhor" escreveriam isso como

$ awk '/^.\./ { $0 = "0" $0 } 1' file.txt

(e provavelmente também remover a maioria dos espaços: awk '/^.\./{$0="0"$0}1' file.txt)


1
+1 Seu último exemplo do AWK ou seu exemplo sed são as maneiras corretas de fazer isso. Observe, para maior clareza, que seria apenas um ou outro.
— Pausado até novo aviso.

Na minha opinião, a abordagem "correta" (que não mexe em espaços e, de qualquer maneira, é mais leve) é a sua versão final sed 's/^.\./0&/' file.txt,. Eu acho que você deveria colocar isso no início desta resposta. Ainda assim, +1.
— Curinga

1
@Wildcard Nosso objetivo é agradar.
— Kusalananda

5

Com sed:

sed -e "/^.\./s/^/0/" file.txt 

O padrão /^.\./procura qualquer caractere e um ponto literal no início da linha ^e, se isso corresponder, ssubstitua o início da linha por um zero, adicionando efetivamente o zero ao início.

O sed expressoin s/.\{0\}/0/é um tanto estranho, corresponde a zero ou mais cópias de qualquer coisa e é substituído por um zero. É claro que o padrão corresponderá em todas as posições da sequência, mas como s///apenas substitui a primeira correspondência, ele funcionará conforme o desejado. Uma maneira singular de fazer isso, no entanto.


Ou com o awk, uma regex semelhante funcionaria para corresponder à linha, mas podemos usar substr:

awk 'substr($0, 2, 1) == "." {$0 = "0" $0} 1' file.txt 

Primeiro testamos se o segundo caractere é um ponto e, em seguida, adicionamos um zero à frente da linha. A final invoca a ação padrão de imprimir a linha após quaisquer modificações.


4

Você disse awk e sed, mas parece que você está tentando formatar uma data e, para isso, eu usaria o datecomando Por exemplo:

echo '1.2.2017 23:40:00' | sed 's/\./\//g' | xargs -0 date '+%m.%d.%Y %T' -d

irá produzir

01.02.2017 23:40:00

O sedcomando no meio altera os períodos para barras para entrada date -d. As opções de formato permitem a saída em praticamente qualquer formato desejado. O %mem particular irá zerar o mês, que é o que parece que você está tentando fazer.

Como Kusalananda aponta:

Ainda mais compacto (data GNU e Bash): date -f <(tr '.' '/' <dates.in) '+%m.%d.%Y %T'


2
Boa pegada! Ainda mais compacto (data GNU e Bash):date -f <(tr '.' '/' <dates.in) '+%m.%d.%Y %T'
— Kusalananda

Sempre que tenho Slashes em meus padrões, mas não Canos s|\.|/|g. Caso contrário, como observado acima: Nice catch, +1
— Alex Stragies

2

Uma estratégia diferente da apresentada nas outras respostas: você pode usar "." como o separador de campos.

awk -F. '$1 < 10 {printf "0"} {print}' /tmp/in.txt

Você pode jogar isso para:

awk -F. '$1<10{printf "0"}1' /tmp/in.txt

Para sed, há um comando mais curto, apresentado em outra (ótima) resposta.


1
Alternativa: awk -F. '{print ($1<10?0$0:$0)}' file
— George Vasiliou

1

Com sed poderia ser

sed 's/^\(.\)\.\(.*\)/0\1.\2/'

Isso será usado ^para ancorar no início da linha e, em seguida, capturar qualquer caractere único em um grupo, seguido por um literal .e depois qualquer outra coisa. Se combinarmos que imprimimos a 0, nosso primeiro grupo de capturas (o caractere no início da linha) e, em seguida ., nosso segundo grupo de capturas (o restante da linha)


Não é necessário fazer nada disso. &é seu amigo. Veja o exemplo sed de Kusalananda.
— Pausado até novo aviso.

@DennisWilliamson não é necessário, mas dado que já existem outros exemplos isso mostra outra característica sedque poderia ser útil em outras situações, não apenas este problema específico
— Eric Renouf
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.