Como imprimir todas as colunas após um determinado número usando awk?

90

No shell, eu canalizo para awk quando preciso de uma coluna específica.

Isso imprime a coluna 9, por exemplo:

... | awk '{print $9}'

Como posso dizer ao awk para imprimir todas as colunas, incluindo e após a coluna 9 , não apenas a coluna 9?

lazer
fonte

Respostas:

83
awk '{ s = ""; for (i = 9; i <= NF; i++) s = s $i " "; print s }'
Amadan
fonte
3
alguns pequenos refinamentos:awk -v N=9 '{sep=""; for (i=N; i<=NF; i++) {printf("%s%s",sep,$i); sep=OFS}; printf("\n")}'
glenn jackman
Obrigado @glenn, isso é um pouco mais geral. De qualquer forma, eu definitivamente concordaria que seria melhor usar cutou perlpara isso. Use-o apenas se você realmente insistir em colocá-lo awk.
Amadan
1
@SiegeX: Não adiciona bytes NUL, deixa o FS no lugar entre cada campo vazio.
Dennis Williamson
1
Por favor, veja a resposta de @ Ascherer para elegância.
3
@veryhungrymike: Elegância é bom, mas prefiro estar correto. : p
Amadan
68

Quando você deseja fazer uma variedade de campos, awkrealmente não tem uma maneira direta de fazer isso. Eu recomendaria em cutvez disso:

cut -d' ' -f 9- ./infile

Editar

Adicionado delimitador de campo de espaço devido ao padrão ser uma guia. Obrigado a Glenn por apontar isso

SiegeX
fonte
15
Uma coisa sobre o corte é que ele usa um delimitador específico (tab por padrão), onde awk usa "espaço em branco". Com o corte, 2 tabulações consecutivas delimitam um campo vazio.
glenn jackman
1
Como @glennjackman apontou, o delimitador do awk é o "espaço em branco" (qualquer valor também). Portanto, definir o delimitador de corte para um espaço único não corresponderia ao comportamento também. infelizmente, o loop é o melhor que se pode fazer, então parece.
poncha de
Este não funciona corretamente. Experimente o comando find . | xargs ls -l | cut -d' ' -f 9-. Por alguma razão, os espaços duplos também são contados. Exemplo: lrwxrwxrwx 1 me me 21 Dec 12 00:00 ./file_a lrwxrwxrwx 1 me me 64 Dec 6 00:06 ./file_bresultará em./file_a 00:06 ./file_b
Marco Pashkov,
@MarcoPashkov, por favor, explique Este não funciona corretamente , especialmente considerando que você usa exatamente o mesmo código em seu pipeline. A propósito, você nunca
SiegeX
cortar não faz o trabalho aqui. Por exemplo, se sua entrada for "foo bar" (espaço único) para uma linha e "foo ___ bar" (ou seja, vários espaços, mas SO é muito inteligente para mostrá-lo) para outra, o cut irá processá-los de forma diferente.
UKMonkey
54
awk '{print substr($0, index($0,$9))}'

Editar : Observe que isso não funciona se qualquer campo antes do nono contiver o mesmo valor do nono.

Ascherer
fonte
10
@veryhungrymike: ... e não funciona se qualquer campo antes do nono contiver o mesmo valor do nono.
Amadan 01 de
6
Provavelmente por causa da frase clássica "espero que seu arquivo não tenha esse problema". É um total não-não em s / w de engenharia para o estado: "nós não vamos perder tempo inclusive para a entrada de por exemplo, valores negativos de verificação de erros, porque 'nós esperamos que o usuário será suficiente inteligente para não julgá-los fora, travando nossa ferramenta '". HAHAHA! Sempre adoro ouvir isso! (I como um bom senso de humor) Bem, como idiotas fazer existe, é dever do desenvolvedor para fazer o seu material à prova de idiotas ! Em vez de "esperar o bem do homem". Essa é uma atitude esperada de filósofos, não engenheiros s / w ... LOL
erro de sintaxe
3
Eu não estava dizendo para não verificar se há erros, mas se você sabe que não terá o problema, essa solução é adequada, como afirmei. Mas obrigado pelo downvote desnecessário de @syntaxerror. Esta solução funcionará para alguns, como os (atualmente) 19 votos positivos irão mostrar, mas se não funcionar, então não use para sua solução. Existem várias maneiras de resolver o problema do OP.
Ascherer
1
Se você estiver usando awk na linha de comando em seu trabalho diário, esta é definitivamente a solução que você deseja. Não é óbvio? A verificação de erros, etc, realmente não importa nesse caso, já que você está digitando e pode pegar esse tipo de coisa antes de pressionar enter (pessoalmente, não acho que awk deva ser usado para qualquer outra coisa, de qualquer maneira, é por isso que nós tenho perl, python, tcl e cerca de 100 outras linguagens de script melhores, mais rápidas e menos irritantes!) Claro, talvez eu esteja dando aos meus colegas desenvolvedores de software muito crédito e eles realmente precisam de verificação de erros, mesmo nas coisas que digitam em tempo real (??)
osirisgothra
1
Não que precisasse, pois está logo abaixo da resposta, mas eu adicionei @atti
Ascherer
11
sed -re 's,\s+, ,g' | cut -d ' ' -f 9-

Em vez de lidar com espaços em branco de largura variável, substitua todos os espaços em branco como um único espaço. Em seguida, use simples cutcom os campos de interesse.

Ele não usa awk, então não é pertinente, mas parecia apropriado dadas as outras respostas / comentários.

Algum tolo
fonte
1
Por favor, torne sua resposta mais abrangente, caso contrário poste isso como um comentário à pergunta.
Alper Turan
Isso é ideal para ps faux | uso. Nunca tenha medo de admitir que a ferramenta XYZ não seja a mais adequada.
kevinf
10

Geralmente perl substitui awk / sed / grep et. al., e é muito mais portátil (além de ser apenas um canivete melhor).

perl -lane 'print "@F[8..$#F]"'

Timtowtdi se aplica, é claro.

Bobbogo
fonte
Você precisa adicionar a opção de linha de comando -lou adicionar \nà instrução de impressão.
glenn jackman
@glenn jackman: Possivelmente. Não requerido se for parte de outra mensagem, ou sendo atribuído a uma variável etc. No que diz respeito a "melhor", perl certamente fica melhor no pequeno. Pode parecer muito desarrumado no grande, admito.
bobbogo
Não me entenda mal, eu gosto do Perl. Eu amo o awk pelo que ele é.
glenn jackman
Meu dispositivo embutido não vem com Perl, mas tem awk.
Sepero de
Downvoting porque a questão perguntava como fazer isso no awk, e não no perl, ruby, java, python, bash.
Tom Harrison
3
awk -v m="\x01" -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 Ascherer.

Defina uma função:

fromField () { 
awk -v m="\x01" -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 finais Para N = 0 ela retorna a linha inteira, como está, e para n> NF a string vazia

Robert Vila
fonte
Essa é uma boa ideia. Não funciona muito bem em um Mac atual usando o gawk típico, porque $ 0 entra em colapso. A correção é definir uma variável para $ 0 como a primeira etapa, como: '{s = $ 0; ... imprimir substr (s, índice (s, m) +1}
joelparkerhenderson
1

Aqui está um exemplo de ls -lsaída:

-rwxr-----@ 1 ricky.john  1493847943   5610048 Apr 16 14:09 00-Welcome.mp4
-rwxr-----@ 1 ricky.john  1493847943  27862521 Apr 16 14:09 01-Hello World.mp4
-rwxr-----@ 1 ricky.john  1493847943  21262056 Apr 16 14:09 02-Typical Go Directory Structure.mp4
-rwxr-----@ 1 ricky.john  1493847943  10627144 Apr 16 14:09 03-Where to Get Help.mp4

Minha solução para imprimir qualquer coisa $9éawk '{print substr($0, 61, 50)}'

Rickydj
fonte
0
ruby -lane 'print $F[3..-1].join(" ")' file
kurumi
fonte
0

Para exibir os 3 primeiros campos e imprimir os campos restantes, você pode usar:

awk '{s = ""; for (i=4; i<= NF; i++) s= s $i : "; print $1 $2 $3 s}' filename

onde $ 1 $ 2 $ 3 são os 3 primeiros campos.

Raymond C Borges Hink
fonte
0
function print_fields(field_num1, field_num2){
    input_line = $0

    j = 1;
    for (i=field_num1; i <= field_num2; i++){
        $(j++) = $(i);

    }
    NF = field_num2 - field_num1 + 1;
    print $0

    $0 = input_line
}
msol01
fonte
0

Usando cut em vez de awk e superando problemas para descobrir em qual coluna começar usando o comando -c character cut.

Aqui estou dizendo, dê-me todos, exceto os primeiros 49 caracteres da saída.

 ls -l /some/path/*/* | cut -c 50-

O /*/*/no final do comando ls está dizendo mostre-me o que há nos subdiretórios também.

Você também pode puxar certos intervalos de caracteres ala (da página de manual de corte). Por exemplo, mostre os nomes e horários de login dos usuários atualmente conectados:

       who | cut -c 1-16,26-38
Joe
fonte