Eu tenho uma saída semelhante a
975 Jan/21 - 19:59:36 ### sed "/^#include_dir/a include_dir = 'conf.d'" /opt/db/data/efa_bauen_ni_14/postgresql.conf
986 Jan/21 - 20:04:21 ### grep -l "^port = '5" /opt/db/data/postgres/efa_bauen_ni/conf.d/*.conf | xargs sed -i "s/port = '5/port = '6/"
agora quero reduzir cada linha a tudo depois $5
, para obter o comando completo real?
Acho que poderia fazer | awk {'print $6, $7, $8, $9, $10, $11'}
... etc. Mas isso parece muito anticientífico, pouco flexível e feio.
Alguém pode me aconselhar como fazer isso ou estou no caminho errado awk
para começar?
Os dados de exemplo parecem ser de um histórico de comando, provavelmente um número de comando, uma data, uma hora, a sequência
###
e então o comando. Nos dados de exemplo, tudo parece se alinhar bem, então o problema se torna "Como me livro dos primeiros 29 caracteres?". Awk não deve ser sua primeira escolha, pois você provavelmente quer preservar lugares onde há mais de um espaço, e isso significa que awk dividir as coisas em campos não é útil para você.é uma maneira de fazer isso. Uma segunda maneira é observar que há uma string fixa
###
, e que não há#
caracteres antes disso. Então você pode usar uma expressão regular para corresponder ao início da linha, zero ou mais caracteres que não são#
, e então a string fixa e removê-los. A vantagem dessa abordagem é que se os dados mudarem, por exemplo, se o número do comando ficar tão grande que uma coluna extra seja necessária para armazenar o valor, nenhuma mudança será necessária neste programa.Você pode usar
gsub
o awk para fazer o mesmo, se realmente quiser usar o awk.Aqui está uma maneira de cortar tudo antes do primeiro
###
com POSIX awk:nota: também descarta as linhas que não contêm
###
Você pode usar
sed
, supondo que###
não apareça várias vezes em uma linha:Saída
Com uma
Perl
linha para imprimir tudo depois da coluna 5:usando uma fatia de matriz .
Ao usar
-a
switch,Perl
comporte-se comoawk
e divida em espaços por padrão em@F
array. Você pode usar também-F
para definir o separador de campo (pode ser um regex).Com
grep
implementações que suportam-o
(para emitir a parte correspondente) e-P
(para expressões regulares do tipo Perl):Imprimiria o que viesse depois da primeira ocorrência de
<whitespace>###<whitespace>
em cada linha.Para imprimir o que vem depois dos primeiros 5 campos delimitados por espaços em branco.
Uma resposta mais genérica, caso alguém tenha uma pergunta semelhante com um conjunto de dados diferente:
A primeira parte
$1=$2=$3=$4=$5=""
define os primeiros 5 campos para o caractere vazio. A desvantagem disso é que o awk ainda lembra que id tinha esses campos, entãoprint $0
deixará um espaço vazio na frente da linha de saída.Assim, a segunda parte
$0=$0
remove os espaços em branco iniciais e finais.A terceira parte
print $0
então imprime a nova linha encurtada.Sim, você está no caminho errado com
awk
. Quer dizer, você pode fazer isso no awk, e eu vou te mostrar como em um momento, mas há outra ferramenta,cut
que é projetada precisamente para isso. Se você quiser imprimir todos os campos do 5º até o último, você pode simplesmente fazer:O
-d ' '
dizcut
para usar um espaço como delimitador porqueut
o padrão é usar TAB. Então, o-f
é usado para dizer quais campos imprimir e aqui estamos dizendo para imprimir do 5º até o final (5-
).Agora, se seu arquivo não estiver bem estruturado, se você puder ter, digamos, um ou mais espaços como delimitador, awk seria a melhor escolha, mas é mais complexo. Você poderia fazer algo assim, por exemplo:
Mas isso ainda alteraria o número de espaços em algo como:
Onde
cut
não iria:Tenho certeza de que você pode obter uma solução awk mais elegante, mas, na verdade,
cut
esta é a ferramenta certa aqui.Usando qualquer awk POSIX:
ou GNU awk para
\s
/\S
:ou POSIX sed:
ou sed que tenha uma
-E
opção para suportar EREs (por exemplo, seds GNU e BSD):ou GNU sed para
-E
e\s
/\S
:awk '{para (i=6;i<=NF;i++) printf("%s%s",(i==6)? "":" ",$i); printf("\n"); } ' arquivo.txt
Usando Raku (anteriormente conhecido como Perl_6)
As respostas do Raku acima foram escritas para complementar a excelente resposta do Perl postada por @GillesQuénot. Para one-liners, o Raku simplifica o número de flags de linha de comando enquanto adiciona mais algumas rotinas para compensar.
-ne
sinalizadores de linha de comando instruem o Raku a executar o código linha a linha sem impressão automática (awk
comportamento semelhante ao )..words
rotina é uma abreviação que$_.words
significa interromper a entrada de texto em espaços em branco..comb
rotina é usada para selecionar globalmente/ \S+ /
um ou mais caracteres que não sejam espaços em branco..[5..*]
e então usá-losput
para gerar a saída resultará na fatia desejada de colunas/elementos impressa, com um (único) caractere de espaço em branco como separador.put
adicionará automaticamente o caractere de nova linha EOL.Exemplo de entrada:
Exemplo de saída:
https://docs.raku.org
https://raku.org