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
G.Ahmet
fonte

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)

Kusalananda
fonte
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.

ilkkachu
fonte
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'

bmb
fonte
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.

Alex Stragies
fonte
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)

Eric Renouf
fonte
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