Variable que no se acepta en awk al pasar de un archivo

Variable que no se acepta en awk al pasar de un archivo

Estoy leyendo un archivo línea por línea. Cada línea se ve así:

xxyu: JHYU_IOPI

Cada línea se pasa a awk como se muestra a continuación. Quiero imprimir la línea anterior del patrón coincidente; Puedo lograr esto con grep y quiero saber dónde cometí un error con awk.

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

También probé esto:

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

Editar: usar awk después de recibir la sugerencia de no usar sh read. Mi entrada y salida deseada se muestran a continuación:

EDITAR 1: editó la entrada para el script awk de @Ed Morton como se muestra a continuación

Archivo de entrada: archivo 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

Rendimiento esperado -

 box_name: AIX_RUN_WATCH
 insert_job: AIX_stop
 insert_job: AIX_start

Respuesta1

para el primer intento , debe usar comillas dobles para la expansión de la variable del shell y luego escapar las del $operador awk para evitar que el shell se expanda, pero tenga en cuenta que usar esto romperá awk en caso de que la variable $icontenga un carácter especial como \,. /[Me salto para solucionar uno o más problemas con su comando ahora].

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

para el segundo intento, necesita usar una coincidencia de expresiones regulares o una coincidencia de cadenas con la línea actual, como usar una coincidencia de expresiones regulares (coincidencia parcial de expresiones regulares) con:

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

o coincidencia de cadena (coincidencia de cadena completa) como:

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

ahora, hablando de los comandos que está intentando utilizar para imprimir la línea anterior del patrón coincidente, puede hacer todo con awk y dejarlo usando el bucle de shell; Aquí estamos haciendo una coincidencia completa de cadenas:

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

o haciendo una coincidencia parcial de expresiones regulares:

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

o haciendo una coincidencia parcial de cadenas:

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

o haciendo una coincidencia completa de expresiones regulares:

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

Respuesta2

No necesitas un ciclo de lectura while para esto, y procesar texto en sh es una mala idea (ver¿Por qué se considera una mala práctica utilizar un bucle de shell para procesar texto?).

En su lugar, obtenga su script awk para procesar ambos archivos.

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

Mientras lee el primer archivo ( in.txt), crea una expresión regular en una variable llamada reagregando cada línea de entrada y la expresión regular "alternancia" (es decirO) operador.

Cuando haya terminado de leer el primer archivo, lo primero que debe hacer es eliminar el final |del archivo re. Esto es necesario reporquesiempreterminar con |carácter debido a la forma en que está construido. Si no lo eliminamos, ese final |hará que la expresión regular coincida con cada línea de ver_in.txt.

Después de eso, imprima la variable asi la línea de entrada actual coincide con la expresión regular en la variable re(esto imprimirá una línea vacía si la primera línea de ver_in.txt coincide re, porque a está vacía. Si no desea que eso suceda, cambie esa línea de $0 ~ re {print a}a $0 ~ re && a != "" {print a}).

Luego, coincida o no, establezca a=$0.

NOTA: NR==FNR {... ; next}es un modismo awk muy común para manejar el primer archivo de entrada de una manera diferente que el segundo archivo de entrada y los siguientes. NRes el contador de líneas global para todos los archivos que se están leyendo y FNRes el contador de líneas para el archivo actual... entonces NR==FNR, si eso significa que estamos leyendo el primer archivo. La nextdeclaración salta a la siguiente línea de entrada, evitando que se ejecute el resto del script awk mientras se encuentra en el primer archivo.

No proporcionaste una muestra de datos completa, así que hice la mía propia para probarla:

$ cat in.txt 
xxyu: JHYU_IOPI
foo
bar

Este archivo in.txt hará que re sea igualbar|foo|xxyu: JHYU_IOPI

Por cierto, debido a que el script awk realiza una coincidencia de expresiones regulares re, las líneas in.txtse tratan como expresiones regulares, no como texto fijo. Eso significa que si desea que los caracteres especiales de expresiones regulares (como ., |o [y ]muchos otros) en in.txt sean tratados como caracteres literales, deberá evitarlos con una barra invertida... habría tenido que hacerlo esto también con tu bucle sh+awk original.

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

Salida del script awk anterior:

a line 1
d line 4
f line 7

Respuesta3

No utilice un bucle de shell para manipular texto, consulte¿Por qué se considera una mala práctica utilizar un bucle de shell para procesar texto?. Las personas que inventaron Shell también inventaron awk para que Shell llamara y manipulara texto.

Usando cualquier awk en cualquier shell en cada caja 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

Respuesta 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

Verhttps://www.gnu.org/software/gawk/manual/gawk.html#Multiple-Linepara ver cómo establecer RS ​​en nulo nos permite trabajar con registros de varias líneas, y luego configurar FS en una nueva línea significa que cada campo en dicho registro es una línea completa, por lo que tratamos sus datos como registros separados por líneas en blanco, cada uno de los cuales contiene 2 líneas de datos.

Mencionaste que tienes algún otro archivo de líneas de lucha que indica cuáles deben imprimirse, lo que implica que hay otros bloques que no deben imprimirse. Si tiene un archivo de este tipo y se ve así:

$ cat targets
ght: ertyjk
ght: YUIOPO

y su otro archivo de entrada contiene algunas ght:líneas que no coinciden con lo anterior, por ejemplo, vea los ght: whateverbloques en el archivo de entrada modificado a continuación:

$ 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

entonces el código anterior se actualizaría a:

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

información relacionada