Bash Script para pegar um arquivo como entrada e executar o comando awk em outro arquivo

0

Eu estou tentando escrever um script que leva um arquivo e executa cada linha como uma string para o comando awk que é executado em outro arquivo. Aqui está o que eu tenho neste momento.

#!/bin/bash

FILE=$1
FILE_TO_SEARCH=$2

exec 4> "FILE_TO_SEARCH"

while read -ru 3 LINE; do
    awk -v RS='' -v ORS='\n\n' "$LINE" <&4
done 3< "$FILE"

Quando tento executar o script, estou recebendo:

./bashscript2.sh: line 8: read: read error: 3: Bad file descriptor

O arquivo (FILE) que ele estaria pesquisando teria um conteúdo como este:

hostAbC
host123
host345
hostMos
hostDef

O qual então executaria o comando awk em um arquivo (FILE_TO_SEARCH) com conteúdos parecidos com aquele abaixo, exceto muito mais.

* * * * * * * * *  * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

 id: urn:storageos:Initiator:
    clustername = BLAHBLAHBLAH
    creationTime = java.util.GregorianCalendar[
                time=1490279415811
                2017-03-23 14:30:15 811ms UTC
,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2017,MONTH=2,WEEK_OF_YEAR=12,WEEK_OF_MONTH=4,DAY_OF_MONTH=23,DAY_OF_YEAR=82,DAY_OF_WEEK=5,DAY_OF_WEEK_IN_MONTH=4,AM_PM=1,HOUR=2,HOUR_OF_DAY=14,MINUTE=30,SECOND=15,MILLISECOND=811,ZONE_OFFSET=0,DST_OFFSET=0]
    host = URI: 
    hostname = hostAbC
    inactive = false
    ininode = 01:01:01:01:01:01:01:01
    iniport = 01:01:01:01:01:01:01:01
    internalFlags = 0
    isManualCreation = true
    label = 01:01:01:01:01:01:01:01
    status = OpStatusMap {}
    protocol = FC
    registrationStatus = REGISTERED


 * * * * * * * * *  * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

 id: urn:storageos:Initiator:
    clustername = YADAYADAYADA
    creationTime = java.util.GregorianCalendar[
                time=1485972630239
                2017-02-01 18:10:30 239ms UTC
,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2017,MONTH=1,WEEK_OF_YEAR=5,WEEK_OF_MONTH=1,DAY_OF_MONTH=1,DAY_OF_YEAR=32,DAY_OF_WEEK=4,DAY_OF_WEEK_IN_MONTH=1,AM_PM=1,HOUR=6,HOUR_OF_DAY=18,MINUTE=10,SECOND=30,MILLISECOND=239,ZONE_OFFSET=0,DST_OFFSET=0]
    host = URI: 
    hostname = hostMos
    inactive = false
    ininode = 01:01:01:01:01:01:01:01
    iniport = 01:01:01:01:01:01:01:01
    internalFlags = 0
    isManualCreation = false
    label = 01:01:01:01:01:01:01:01
    status = OpStatusMap {}
    protocol = FC
    registrationStatus = REGISTERED


* * * * * * * * *  * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

O comando awk awk -v RS='' -v ORS='\n\n' encontraria a entrada hostAbC e retornaria a entrada completa do espaço para o espaço.

Eu não consigo descobrir como fazer isso funcionar.

    
por Juan Aguilera 20.01.2018 / 20:28

2 respostas

0

Como observado em meu comentário, a menos que exista algo que você não tenha nos contado, não parece haver necessidade de usar descritores de arquivos além de stdin e stdout aqui, nem há qualquer razão para não apenas passar os nomes de arquivos para awk na linha de comando.

E gravar um loop while read do shell para executar awk várias vezes no mesmo arquivo de entrada é uma maneira realmente difícil de fazer o que você está tentando fazer - possivelmente a pior maneira possível de processar arquivos de texto. Serão centenas ou milhares de vezes mais lentas do que fazer a mesma tarefa no awk (ou sed ou perl, etc.).

Tente algo assim:

#!/bin/bash

FILE1="$1"
FILE_TO_SEARCH="$2"

awk 'NR==FNR { gsub(/([\.^$(){}\[\]|*+?])/,"\\&",$0);
               if (search == "") {
                 search = $0;
               } else {
                 search = search "|" $0;
               };
               next;
             };

     match($0,search)' "$FILE1" RS='' ORS='\n\n' "$FILE_TO_SEARCH"

(feeds de linha, recuo adicionado para legibilidade. a parte awk deste trabalho é toda comprimida em uma linha também)

Isso imprimirá todos os registros em $FILE_TO_SEARCH que correspondem a qualquer um dos padrões de pesquisa em $FILE1 .

Ele lê o primeiro arquivo ( $FILE1 ) usando o padrão RS & ORS e constrói um padrão de procura de expressão regular a partir dele. A chamada da função gsub() é usada para excluir todos os meta-caracteres da expressão regular antes de cada linha ser anexada ao padrão de pesquisa, ou seja, todas as linhas são tratadas como sequências fixas. Se você quiser que cada linha seja uma expressão regular, consulte a segunda versão abaixo.

Com sua amostra $FILE1 acima, o padrão de pesquisa será:

hostAbC|host123|host345|hostMos|hostDef 

Em seguida, usando RS='' e ORS='\n\n' , ele lê o segundo arquivo ( $FILE_TO_SEARCH ) e imprime qualquer registro que corresponda ao padrão de pesquisa.

A seguinte versão pode ser usada se você quiser que cada linha de $FILE1 seja interpretada como uma expressão regular em vez de uma string fixa:

#!/bin/bash

FILE1="$1"
FILE_TO_SEARCH="$2"

awk 'NR==FNR { if (search == "") {
                 search = "(" $0 ")" ;
               } else {
                 search = search "|(" $0 ")";
               };
               next;
             };

     match($0,search)' "$FILE1" RS='' ORS='\n\n' "$FILE_TO_SEARCH"

O padrão de pesquisa da amostra com esta versão seria:

(hostAbC)|(host123)|(host345)|(hostMos)|(hostDef)

Observe que, com essa versão, é possível construir facilmente um padrão de pesquisa interrompido que não corresponda a nada ou que corresponda demais. Você precisará usar a barra invertida para escapar de quaisquer meta-caracteres regex em $ FILE1 que você queira que sejam interpretados como sequências literais. por exemplo. Se você quiser combinar um literal | , ele deve estar no arquivo como \| , caso contrário, ele será interpretado como um operador de alternância regex OR .

    
por 21.01.2018 / 05:24
1
exec 4> "FILE_TO_SEARCH"

O problema é que você abre o arquivo apenas para gravação (excluindo seu conteúdo por isso), mas tenta usar o descritor de arquivo para leitura.

exec 4< "$FILE_TO_SEARCH"
    
por 20.01.2018 / 20:30