Como imprimir a terceira coluna na última coluna?

121

Estou tentando remover as duas primeiras colunas (nas quais não estou interessado) de um arquivo de log DbgView. Não consigo encontrar um exemplo que imprima da coluna 3 em diante até o final da linha. Observe que cada linha possui um número variável de colunas.

Amit G
fonte
possível duplicata de Usando awk para imprimir todas as colunas do enésimo ao último
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Respostas:

108

... ou uma solução mais simples: cut -f 3- INPUTFILE basta adicionar o delimitador correto (-d) e você terá o mesmo efeito.

Marcin
fonte
9
Observe que isso só funciona se o delimitador for exatamente o mesmo entre todas as colunas ... Por exemplo, você não pode usar recortar com um delimitador como \ d +. (Que eu saiba.)
Zach Wily
72
Quando a pergunta é intitulada awk, é inapropriado aceitar uma resposta diferente de awk. E se as pessoas precisarem dele para scripts awk? Essa resposta deveria ser apenas um comentário.
syaz 01 de
24
@SyaZ: Normalmente eu concordaria, mas com a quantidade de 'awk gratuito' acontecendo neste fórum, achei que fosse necessário mostrar uma maneira alternativa de fazer a tarefa. Você não ficaria grato se alguém lhe mostrasse uma maneira mais simples e rápida de fazer a mesma tarefa? Talvez o autor do cartaz tenha pensado que awk é a única maneira de fazer isso por causa do número de respostas 'não incorretas, mas certamente improváveis ​​após' a outras perguntas?
Marcin
12
É para isso que serve o comentário. Aceite a melhor resposta do awk e forneça melhores sugestões de não awk nos comentários. Se as pessoas começarem a postar respostas que não respondem exatamente às perguntas, será irritante ao pesquisar (no meu caso).
syaz
12
Não apenas o delimitador deve ser o mesmo entre todas as colunas, mas deve haver EXATAMENTE UM caractere delimitador entre as colunas. Portanto, se você estiver lidando com programas que alinham sua saída com delimitadores, é melhor usar o awk.
sknaumov de
112
awk '{for(i=3;i<=NF;++i)print $i}' 
Jonathan Feinberg
fonte
3
awk '{for (i = 3; i <= NF; ++ i) print $ i}' seja mais compacto. :)
user172818
1
Obrigado, lh3. Eu estava apenas copiando e colando para o manual do gawk. :)
Jonathan Feinberg
23
isso falha com várias linhas, cada coluna é tratada como uma nova linha quando impressa na impressão
meso_2600
13
Para resolver o problema de saída dividida, proponho esta solução: awk '{for(i=3;i<=NF;++i)printf $i""FS ; print ""}'( printfnão imprimirá o caractere de nova linha, mas print ""adicionarei a nova linha depois que os outros campos forem impressos)
lauhub
1
Ou: echo $(seq 1 10) | awk '{for (i=3; i<=NF; i++) printf $i FS}', o que dá: 3 4 5 6 7 8 9 10.
x-yuri
106
awk '{ print substr($0, index($0,$3)) }'

solução encontrada aqui:
http://www.linuxquestions.org/questions/linux-newbie-8/awk-print-field-to-end-and-character-count-179078/

daisaa
fonte
23
Estou meio atrasado para isso, mas isso não funcionará para registros em que o primeiro ou o segundo campo é igual ao terceiro (por exemplo, 3 2 3 4 5)
aleph_null
imprimir um intervalo interno também é possível: `` `# de $ 3 (incluído) a $ 6 (excluído); echo "1,2,3,4,5,6,7,8,9" | awk 'BEGIN {FS = ","; OFS = ","} {print substr ($ 0, index ($ 0, $ 3), length ($ 0) -index ($ 0, $ 6) -1)}'; # dá 3,4,5```
splaisan
34

A resposta de Jonathan Feinberg imprime cada campo em uma linha separada. Você pode usar printfpara reconstruir o registro para saída na mesma linha, mas também pode simplesmente mover os campos um salto para a esquerda.

awk '{for (i=1; i<=NF-2; i++) $i = $(i+2); NF-=2; print}' logfile
Pausado até novo aviso.
fonte
1
Esteja ciente de que isso só funciona para Gnu awk, decrementar NFnão é permitido pelo POSIX.
kvantour
1
@kvantour: Funciona em gawk, mawk, MacOS awk (nawk?). POSIX parece não saber se NFpode ser diminuído.
Pausado até novo aviso.
É um desses cantos escuros engraçados do awk .
kvantour
19
awk '{$1=$2=$3=""}1' file

NB: este método deixará "espaços em branco" em 1,2,3 campos, mas não é um problema se você quiser apenas olhar a saída.

ghostdog74
fonte
Execute esse comando com `| sed s / ^ \ * // | coluna -t` para retirar os espaços iniciais e alinhar as colunas restantes
MSpreij
O que significa o último 1? com qual palavra-chave devo pesquisar awk?
Itachi
@Itachi veja o exemplo 1 de catonmat.net/blog/awk-one-liners-explained-part-one
kvantour
1
@Nathan você resolve este problema como{$1=$2=$3="";$0=$0;$1=$1}1
kvantour
11

Se você quiser imprimir as colunas após o terceiro, por exemplo, na mesma linha, você pode usar:

awk '{for(i=3; i<=NF; ++i) printf "%s ", $i; print ""}'

Por exemplo:

Mar 09:39 20180301_123131.jpg
Mar 13:28 20180301_124304.jpg
Mar 13:35 20180301_124358.jpg
Feb 09:45 Cisco_WebEx_Add-On.dmg
Feb 12:49 Docker.dmg
Feb 09:04 Grammarly.dmg
Feb 09:20 Payslip 10459 %2828-02-2018%29.pdf

Vai imprimir:

20180301_123131.jpg
20180301_124304.jpg
20180301_124358.jpg
Cisco_WebEx_Add-On.dmg
Docker.dmg
Grammarly.dmg
Payslip 10459 %2828-02-2018%29.pdf

Como podemos ver, o holerite mesmo com espaço, aparece na linha correta.

Irmão
fonte
Rápido e elegante. Obrigado;)
9nz9 de
Isso é excelente, exceto que tenho um problema com a exclusão de $ NF. Quando defino a condição (<= NF), obtenho o último campo, mas o primeiro caractere do primeiro campo é cortado. Estou entendendo mal em termos de funcionalidade?
Ken Ingram
Parece que meu problema é que ^ M está preso no final da última coluna. Não vejo como removê-lo.
Ken Ingram
8

Que tal a seguinte linha:

awk '{$ 1 = $ 2 = $ 3 = ""; imprimir arquivo

Com base na sugestão de @ ghostdog74. O meu deve se comportar melhor quando você filtra linhas, ou seja:

awk '/ ^ exim4-config / {$ 1 = ""; imprimir arquivo
Wawrzek
fonte
Curto e simples. Também pode canalizar e adicionar sed 's/\s\+//g'no final do comando para cortar espaços à esquerda
jumping_monkey
8
awk -v m="\x0a" -v N="3" '{$N=m$N ;print substr($0, index($0,m)+1)}'

Isso corta o que está antes do campo especificado nr., N, e imprime todo o resto da linha, incluindo o campo nr.N e mantém o espaçamento original (não reformata). Não importa se a string do campo aparece também em algum outro lugar da linha, que é o problema com a resposta de daisaa.

Defina uma função:

fromField () { 
awk -v m="\x0a" -v N="$1" '{$N=m$N; print substr($0,index($0,m)+1)}'
}

E use-o assim:

$ echo "  bat   bi       iru   lau bost   " | fromField 3
iru   lau bost   
$ echo "  bat   bi       iru   lau bost   " | fromField 2
bi       iru   lau bost 

A saída mantém tudo, incluindo espaços à direita

Funciona bem para arquivos onde '/ n' é o separador de registro, então você não tem aquele caractere de nova linha dentro das linhas. Se você quiser usá-lo com outros separadores de registro, use:

awk -v m="\x01" -v N="3" '{$N=m$N ;print substr($0, index($0,m)+1)}'

por exemplo. Funciona bem com quase todos os arquivos, desde que não usem hexadecimal char nr. 1 dentro das linhas.

Robert Vila
fonte
4

O seguinte comando awk imprime os últimos N campos de cada linha e no final da linha imprime um novo caractere de linha:

awk '{for( i=6; i<=NF; i++ ){printf( "%s ", $i )}; printf( "\n"); }'

Encontre abaixo um exemplo que lista o conteúdo do diretório / usr / bin e, em seguida, contém as últimas 3 linhas e, em seguida, imprime as últimas 4 colunas de cada linha usando awk:

$ ls -ltr /usr/bin/ | tail -3
-rwxr-xr-x 1 root root       14736 Jan 14  2014 bcomps
-rwxr-xr-x 1 root root       10480 Jan 14  2014 acyclic
-rwxr-xr-x 1 root root    35868448 May 22  2014 skype

$ ls -ltr /usr/bin/ | tail -3 | awk '{for( i=6; i<=NF; i++ ){printf( "%s ", $i )}; printf( "\n"); }'
Jan 14 2014 bcomps 
Jan 14 2014 acyclic 
May 22 2014 skype
funk
fonte
4
awk '{a=match($0, $3); print substr($0,a)}'

Primeiro você encontra a posição do início da terceira coluna. Com substr você imprimirá toda a linha ($ 0) começando na posição (neste caso a) até o final da linha.

Mitchjol
fonte
3

Bem, você pode obter facilmente o mesmo efeito usando uma expressão regular. Presumindo que o separador seja um espaço, seria semelhante a:

awk '{ sub(/[^ ]+ +[^ ]+ +/, ""); print }'
Eddie Sullivan
fonte
1
Eu evitaria regex. Provavelmente é mais lento e fácil de bagunçar acidentalmente.
Cascabel
1
É encurtado assim: o awk '{ sub(/([^ ]+ +){2}/, ""); print }'que tira o padrão duas vezes.
erik
3
awk '{print ""}{for(i=3;i<=NF;++i)printf $i" "}'
luigi9876
fonte
2

Solução Perl:

perl -lane 'splice @F,0,2; print join " ",@F' file

Estas opções de linha de comando são usadas:

  • -n faça um loop em cada linha do arquivo de entrada, não imprima automaticamente todas as linhas

  • -l remove novas linhas antes do processamento e as adiciona de volta depois

  • -amodo autosplit - divide as linhas de entrada no array @F. O padrão é divisão em espaços em branco

  • -e execute o código perl

splice @F,0,2 remove claramente as colunas 0 e 1 da matriz @F

join " ",@F junta os elementos da matriz @F, usando um espaço entre cada elemento

Se o seu arquivo de entrada for delimitado por vírgulas, em vez de delimitado por espaço, use -F, -lane


Solução Python:

python -c "import sys;[sys.stdout.write(' '.join(line.split()[2:]) + '\n') for line in sys.stdin]" < file

Chris Koknat
fonte
1

Um pouco tarde aqui, mas nenhuma das opções acima pareceu funcionar. Tente isso, usando printf, insere espaços entre cada um. Eu escolhi não ter nova linha no final.

awk '{for(i=3;i<=NF;++i) printf("%s ",  $i) }'
Ross
fonte
1
awk '{for (i=4; i<=NF; i++)printf("%c", $i); printf("\n");}'

imprime registros começando do 4º campo ao último campo na mesma ordem em que estavam no arquivo original

Massimo
fonte
desculpe, esta não era uma resposta totalmente correta. é muito específico, mas não sei como excluí-lo
Massimo
1

No Bash, você pode usar a seguinte sintaxe com parâmetros posicionais:

while read -a cols; do echo ${cols[@]:2}; done < file.txt

Saiba mais: Manipulação de parâmetros posicionais no Bash Hackers Wiki

Kenorb
fonte
0

Se for apenas para ignorar os dois primeiros campos e se você não quiser um espaço ao mascarar esses campos (como algumas das respostas acima fazem):

awk '{gsub($1" "$2" ",""); print;}' file
Champost
fonte
0
awk '{$1=$2=""}1' FILENAME | sed 's/\s\+//g'

As duas primeiras colunas são apagadas, sedremove os espaços iniciais.

sjas
fonte
-2

Em AWK, as colunas são chamadas de campos, portanto, NF é a chave

todas as linhas:

awk -F '<column separator>' '{print $(NF-2)}' <filename>

apenas primeira linha:

awk -F '<column separator>' 'NR<=1{print $(NF-2)}' <filename>
angelo.mastro
fonte