AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 557611
Accepted
Johnny Tam
Johnny Tam
Asked: 2019-12-17 18:57:52 +0800 CST2019-12-17 18:57:52 +0800 CST 2019-12-17 18:57:52 +0800 CST

Usando awk remove colunas que são "-" na primeira linha

  • 772

eu tenho a mesa

M       -       A       A       -
-       A       G       -       -
M       -       -       -       G

e quero realizar: se alguma coluna da primeira linha contiver "-", pule a impressão da coluna

A saída esperada é

M       A       A 
-       G       - 
M       -       - 

ja tentei algo assim mas nao funcionou

awk 'NR==1 && $i!="-" {print $i}'

Alguém sabe como corrigir o comando?

awk text-processing
  • 5 5 respostas
  • 377 Views

5 respostas

  • Voted
  1. Ed Morton
    2019-12-18T11:25:53+08:002019-12-18T11:25:53+08:00
    $ cat tst.awk
    NR == 1 {
        for (i=1; i<=NF; i++) {
            if ($i != "-") {
                f[++numOutFlds] = i
            }
        }
    }
    {
        for (i=1; i<=numOutFlds; i++) {
            printf "%s%s", $(f[i]), (i<numOutFlds ? OFS : ORS)
        }
    }
    
    $ awk -f tst.awk file
    M A A
    - G -
    M - -
    
    • 3
  2. Best Answer
    Kusalananda
    2019-12-18T11:39:28+08:002019-12-18T11:39:28+08:00

    Uma variação da resposta de Ed Morton , que lembra quais campos não estão -na primeira linha pelo número do campo e, em seguida, reformula cada registro na entrada de acordo com os índices salvos no array outantes de imprimir o novo registro:

    FNR == 1 {
        for (i = 1; i <= NF; ++i)
            if ($i != "-") out[++nf] = i
    }
    
    {
        for (i = 1; i <= nf; ++i)
            a[i] = $(out[i])
    
        $0 = ""
    
        for (i = 1; i <= nf; ++i)
            $i = a[i]
    
        print
    }
    

    Aqui, sacrifiquei um pouco de eficiência para facilitar a leitura, reconstruindo o registro em um loop separado, em vez de imprimir os campos obrigatórios em um único loop no segundo bloco.

    Teste:

    $ awk -f script.awk file
    M A A
    - G -
    M - -
    

    Executando com guias como separador de campo de saída:

    $ awk -v OFS='\t' -f script.awk file
    M       A       A
    -       G       -
    M       -       -
    

    Uma linha um pouco longa demais que depende dos dados de entrada serem delimitados por tabulação:

    $ cut -f "$(awk -v OFS=',' '{ nf=split($0,a); $0=""; for (i=1; i<=nf; ++i) if (a[i]!="-") $(++NF)=i; print; exit }' file)" file
    M       A       A
    -       G       -
    M       -       -
    

    Isso é usado awkpara gerar os números de campo que não estão -na primeira linha como uma lista separada por vírgulas. Esta lista é então entregue a cut -fquem faz a saída real dos dados do arquivo. Observe que o nome do arquivo (aqui simplesmente file) é fornecido duas vezes na linha de comando, uma vez para awke novamente para cut.

    • 3
  3. dave_thompson_085
    2019-12-18T00:49:33+08:002019-12-18T00:49:33+08:00

    awkfaz um loop implícito sobre registros de entrada (linhas) e arquivos, mas não campos que você deve fazer explicitamente. No seu caso, você precisa percorrer os campos na primeira linha (cabeçalho) para decidir quais colunas incluir e, em seguida, percorrer os campos em cada linha (cabeçalho e não cabeçalho) para incluir as colunas desejadas nessa linha.

    Você não está claro se deseja procurar campos de cabeçalho iguais a (a string) "-" ou que podem tê-lo como uma (sub)string . Eu também suponho que você tenha (todas) guias únicas como separadores de campo, não vários espaços que seriam mais tediosos (e não podem ser distinguidos visualmente de sua postagem).

    awk -F"\t" 'NR==1{for(i=1;i<=NF;i++)s[i]=$i!="-"} {x="";for(i=1;i<=NF;i++)if(s[i])x=x FS $i;print substr(x,2)}'
    # for _matches_ "-" instead of _equals_ "-" change $i!="-" to $i!~/-/
    # note if a nonheader line has more fields than the header did,
    # all extra fields are nonselected (as if their header field was/matched -)
    
    # or (re)use the flags for both what to include _and_ when to terminate the line
    awk -F"\t" 'NR==1{t=RS;for(i=NF;i;i--)if(s[i]=($i!="-"?t:""))t=FS} {for(i=1;i<=NF;i++)if(s[i])printf "%s%s",$i,s[i]}'
    # some people may consider this too clever
    
    • 1
  4. Rakesh Sharma
    2019-12-18T15:43:48+08:002019-12-18T15:43:48+08:00

    Usando Perl.

    Para a primeira linha, construa uma matriz @Ade índices para os quais o campo não é traço.

    Então, para todas as linhas, incluindo a primeira, imprima apenas os campos @Fcujos índices estão em @A.

    $ perl -lane '$, = "\t";
        $. == 1 and @A = grep $F[$_] ne "-", 0..$#F;
        print @F[@A];
    ' file
    

    Resultado:

    M   A   A
    -   G   -
    M   -   -
    
    • 0
  5. Rakesh Sharma
    2019-12-18T20:36:04+08:002019-12-18T20:36:04+08:00

    Podemos fazer isso usando sed, embora o código esteja com GNU sed no modo regex estendido, mas isso é apenas uma cura para o backslashitis.

    O método é criar um mapa da primeira linha. Os campos a serem mantidos são mapeados como x outros como um traço. Salve este mapa no porão.

    Então, para todas as linhas, anexe este mapa e coloque um marcador no BOL.

    Em um loop, continuamos excluindo o campo inicial da linha atual se vemos um \n- E avançamos o marcador para o próximo campo.

    O loop termina quando este marcador colide com a nova linha entre a linha atual e o espaço de espera (devido ao comando G).

    $ sed -Ee '
        1{
          h
          y/-/\n/
          s/\S+/x/g;s/[[:blank:]]+//g
          y/\n/-/
          x
        }
    
        G;s/^/\n/
    
        :a
          s/\n(\S+\s*)(.*\n)x/\1\n\2/
          s/\n(\S+\s*)(.*\n)-/\n\2/
        /\n\n/!ba
    
        s/\s+$//
    ' file
    

    Resultados

    M       A       A
    -       G       -
    M       -       -
    
    • 0

relate perguntas

  • Reorganize as letras e compare duas palavras

  • Subtraindo a mesma coluna entre duas linhas no awk

  • Embaralhamento de arquivo de várias linhas

  • como posso alterar o caso do caractere (de baixo para cima e vice-versa)? ao mesmo tempo [duplicado]

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Possível firmware ausente /lib/firmware/i915/* para o módulo i915

    • 3 respostas
  • Marko Smith

    Falha ao buscar o repositório de backports jessie

    • 4 respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    user12345 Falha ao buscar o repositório de backports jessie 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl Por que a maioria dos exemplos do systemd contém WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve