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 / 674572
Accepted
Renga
Renga
Asked: 2021-10-24 22:12:21 +0800 CST2021-10-24 22:12:21 +0800 CST 2021-10-24 22:12:21 +0800 CST

Variável não aceitando em awk ao passar de um arquivo

  • 772

Estou lendo um arquivo linha por linha. Cada linha fica assim:

xxyu: JHYU_IOPI

Cada linha é passada para o awk como abaixo. Quero imprimir a linha anterior do padrão correspondente; Eu posso conseguir isso com o grep e quero saber onde errei com o awk.

#!/bin/bash
while read i
do
 awk '/$i/{print a}{a=$0}' ver_in.txt
done<in.txt

Eu também tentei isso:

#!/bin/bash
while read i
do
 awk -v var="$i" '/var/{print a}{a=$0}' jil.txt
done<in.txt

Edit: usando awk depois de obter sugestão para não usar sh read. Minha entrada e saída desejada são mostradas abaixo:

EDIT 1: editou a entrada para o script @Ed Morton awk como abaixo

Arquivo de entrada: arquivo cat

/* ----------------- AIX_RUN_WATCH ----------------- */ 

insert_job: AIX_RUN_WATCH   job_type: BOX 
owner: root
permission: 
date_conditions: 1
days_of_week: su
start_times: "22:00"
alarm_if_fail: 1
alarm_if_terminated: 1
group: app
send_notification: 0
notification_emailaddress: 


 /* ----------------- AIX_stop ----------------- */ 

 insert_job: AIXstop   job_type: CMD 
 box_name: AIX_RUN_WATCH
 command: ls
 machine: cfg.mc
 owner: root
 permission: 
 date_conditions: 0
 box_terminator: 1
 std_out_file: ">> /tmp/${AUTOSERV}.${AUTO_JOB_NAME}.$(date +%Y%m%d).stdout"
 std_err_file: ">> /tmp/${AUTOSERV}.${AUTO_JOB_NAME}.$(date +%Y%m%d).stderr"
 alarm_if_fail: 1
 alarm_if_terminated: 1
 group: app
 send_notification: 1


 /* ----------------- AIX_start ----------------- */ 

 insert_job: AIX_start   job_type: CMD 
 box_name: AIX_RUN_WATCH
 command: ls
 machine: cfg.mc
 owner: root
 permission: 
 date_conditions: 0
 box_terminator: 1
 std_out_file: ">> /tmp/${AUTOSERV}.${AUTO_JOB_NAME}.$(date +%Y%m%d).stdout"
 std_err_file: ">> /tmp/${AUTOSERV}.${AUTO_JOB_NAME}.$(date +%Y%m%d).stderr"
 alarm_if_fail: 1
 alarm_if_terminated: 1
 group: app

   cat targets
     box_name: AIX_RUN_WATCH

Saída esperada -

 box_name: AIX_RUN_WATCH
 insert_job: AIX_stop
 insert_job: AIX_start
awk text-processing
  • 3 3 respostas
  • 899 Views

3 respostas

  • Voted
  1. αғsнιη
    2021-10-24T22:54:39+08:002021-10-24T22:54:39+08:00

    para a primeira tentativa, você precisa usar aspas duplas para a expansão da variável do shell e, em seguida, escapar do $operador awk para evitar que ele se expanda pelo shell, mas esteja ciente de que usar como este quebrará o awk caso a variável $icontenha caracteres especiais como \, /. [Estou pulando para corrigir um ou mais problemas com seu comando agora].

    while read i
    do
     awk "/$i/{print a}{a=\$0}" ver_in.txt
    done<in.txt
    

    para a segunda tentativa, você precisa usar correspondência de regex ou correspondência de string na linha atual, como usar correspondência de regex (correspondência parcial de regex) com:

    while read i
    do
     awk -v var="$i" '$0 ~ var{print a}{a=$0}' jil.txt
    done<in.txt
    

    ou correspondência de string (correspondência de string completa) como:

    while read i
    do
     awk -v var="$i" '$0==var{print a}{a=$0}' jil.txt
    done<in.txt
    

    agora, falando sobre os comandos que você está tentando usá-los para imprimir a linha anterior do padrão correspondente, você pode fazer tudo com o awk e parar usando o loop do shell; aqui estamos fazendo uma correspondência de string completa:

    awk 'NR==FNR { str[$0]; next }
    ($0 in str) && prev!="" { print prev } { prev=$0 }' in.txt ver_in.txt
    

    ou fazendo uma correspondência regex parcial:

    awk 'NR==FNR { patt[$0]; next }
    { for(ptrn in patt) if($0 ~ ptrn && prev!="") print prev; prev=$0 }' in.txt ver_in.txt
    

    ou fazendo correspondência de string parcial:

    awk 'NR==FNR { strings[$0]; next }
    { for(str in strings) if(index($0, str) && prev!="") print prev; prev=$0 }' in.txt ver_in.txt
    

    ou fazendo uma correspondência completa de regex:

    awk 'NR==FNR { patt[$0]; next }
    { for(ptrn in patt) if($0 ~ "^"ptrn"$" && prev!="") print prev; prev=$0 }' in.txt ver_in.txt
    
    • 7
  2. cas
    2021-10-24T22:44:53+08:002021-10-24T22:44:53+08:00

    Você não precisa de um loop de leitura while para isso, e fazer processamento de texto em sh é uma má ideia (consulte Por que usar um loop de shell para processar texto é considerado uma prática ruim? ).

    Em vez disso, obtenha seu script awk para processar os dois arquivos.

    awk 'NR==FNR { re = $0 "|" re ; next}; # append input line and | to re
         FNR == 1 { sub(/\|$/,"",re) };    # remove trailing | on 1st line of 2nd file
    
         $0 ~ re { print a }; # if the current line matches re, print a
         {a = $0}' in.txt ver_in.txt
    

    Ao ler o primeiro arquivo ( in.txt), ele cria uma expressão regular em uma variável chamada anexando cada linha de entrada e o operador reregex "alternância" (ou seja, OR ).

    Quando terminar de ler o primeiro arquivo, a primeira coisa que precisa é remover o final |do arquivo re. Isso é necessário porque semprere acabará com caráter devido à forma como é construído. Se não o removermos, esse final fará com que o regex corresponda a todas as linhas de .||ver_in.txt

    Depois disso, imprima a variável ase a linha de entrada atual corresponder ao regex na variável re(isso imprimirá uma linha vazia se a primeira linha de ver_in.txt corresponder re- porque a está vazia. Se você não quiser que isso aconteça, altere essa linha de $0 ~ re {print a}para $0 ~ re && a != "" {print a}).

    Então, se corresponde ou não, defina a=$0.

    NOTA: o NR==FNR {... ; next}é um idioma awk muito comum para manipular o primeiro arquivo de entrada de uma maneira diferente do segundo e dos arquivos de entrada subsequentes. NRé o contador de linha global para todos os arquivos que estão sendo lidos, e FNRé o contador de linha para o arquivo atual.... então se NR==FNR, isso significa que estamos lendo o primeiro arquivo. A nextinstrução pula para a próxima linha de entrada, impedindo que o restante do script awk seja executado enquanto estiver no primeiro arquivo.

    Você não forneceu uma amostra de dados completa, então fiz o meu próprio para testar:

    $ cat in.txt 
    xxyu: JHYU_IOPI
    foo
    bar
    

    Este arquivo in.txt fará com que re seja igualbar|foo|xxyu: JHYU_IOPI

    BTW, porque o script awk está fazendo uma correspondência de regex com re, as linhas in.txtsão tratadas como expressões regulares, não como texto fixo. Isso significa que se você quiser que quaisquer caracteres especiais regex (como ., |, [ou ]e muitos outros) em in.txt sejam tratados como caracteres literais, você precisará escapá-los com uma barra invertida .... você teria que fazer isso com seu loop sh+awk original também.

    $ cat ver_in.txt 
    a line 1
    xxyu: JHYU_IOPI
    b line 3
    d line 4
    bar
    e line 6
    f line 7
    foo
    

    Saída do script awk acima:

    a line 1
    d line 4
    f line 7
    
    • 3
  3. Best Answer
    Ed Morton
    2021-10-26T05:23:35+08:002021-10-26T05:23:35+08:00

    Não use um loop de shell para manipular texto, consulte Por que usar um loop de shell para processar texto é considerado uma prática ruim? . As pessoas que inventaram o shell também inventaram o awk para o shell chamar para manipular texto.

    Usando qualquer awk em qualquer shell em cada caixa Unix:

    $ cat tst.awk
    NR==FNR {
        tgts[$0]
        next
    }
    $0 in tgts {
        if ( $0 != prevTgt ) {
            print $0
            prevTgt = $0
        }
        print prevLine
    }
    { prevLine = $1 FS $2 }
    

    $ awk -f tst.awk targets file
    box_name: AIX_RUN_WATCH
    insert_job: AIXstop
    insert_job: AIX_start
    

    Resposta original:

    awk '
        BEGIN { RS=""; FS="\n" }
        $2 != prev {
            print $2
            prev = $2
        }
        { print $1 }
    ' file
    ght: ertyjk
    xxx: rtyuiol
    xxx: ertyuikl_fghjk
    xxx: qwertyujkl
    xxx: rtyuiol_123
    ght: YUIOPO
    xxx: rtyuiol
    xxx: rtyuiopfghj
    xxx: dfghjkvbnm
    xxx: qzdfghnbvfgh
    xxx: qsxcvghuiokmnhgf
    

    Consulte https://www.gnu.org/software/gawk/manual/gawk.html#Multiple-Line para saber como definir RS para null nos permite trabalhar com registros de várias linhas e, em seguida, definir FS para uma nova linha significa que cada campo em esse registro é uma linha inteira, portanto, estamos tratando seus dados como registros separados por linhas em branco, cada um contendo 2 linhas de dados.

    Você mencionou ter algum outro arquivo de linhas ght que indica quais devem ser impressos, implicando que existem outros blocos que não devem ser impressos. Se você tiver um arquivo desse tipo e se parecer com isso:

    $ cat targets
    ght: ertyjk
    ght: YUIOPO
    

    e seu outro arquivo de entrada contém algumas ght:linhas que não correspondem ao acima, por exemplo, veja os ght: whateverblocos no arquivo de entrada modificado abaixo:

    $ cat file
    xxx: rtyuiol
    ght: ertyjk
    
    xxx: ertyuikl_fghjk
    ght: ertyjk
    
    xxx: qwertyujkl
    ght: ertyjk
    
    xxx: rtyuiol_123
    ght: ertyjk
    
    xxx: foo
    ght: whatever
    
    xxx: bar
    ght: whatever
    
    xxx: rtyuiol
    ght: YUIOPO
    
    xxx: rtyuiopfghj
    ght: YUIOPO
    
    xxx: dfghjkvbnm
    ght: YUIOPO
    
    xxx: qzdfghnbvfgh
    ght: YUIOPO
    
    xxx: qsxcvghuiokmnhgf
    ght: YUIOPO
    

    então o código acima seria atualizado para:

    awk '
        BEGIN { FS="\n" }
        NR==FNR {
            tgts[$0]
            next
        }
        $2 != prev {
            if ( inTgts = ($2 in tgts) ) {
                print $2
            }
            prev = $2
        }
        inTgts { print $1 }
    ' targets RS='' file
    ght: ertyjk
    xxx: rtyuiol
    xxx: ertyuikl_fghjk
    xxx: qwertyujkl
    xxx: rtyuiol_123
    ght: YUIOPO
    xxx: rtyuiol
    xxx: rtyuiopfghj
    xxx: dfghjkvbnm
    xxx: qzdfghnbvfgh
    xxx: qsxcvghuiokmnhgf
    
    • 2

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