читать файл и извлекать переменные в зависимости от того, что в строке - PullRequest
0 голосов
/ 08 февраля 2019

У меня есть файл, который выглядит следующим образом:

$ cat file_test
garbage text A=one B=two C=three D=four
garbage text A= B=six D=seven
garbage text A=eight E=nine D=ten B=eleven

Я хочу просмотреть каждую строку и извлечь конкретные «переменные» для использования в цикле.И если в строке нет переменной, установите ее в пустую строку.

Итак, для приведенного выше примера, скажем, я хочу извлечь переменные A, B и C, тогда для каждой строки цикл будет иметь следующий вид:

  1. garbage text A=one B=two C=three D=four
    • A = "one"
    • B = "two"
    • C =" три "
  2. garbage text A= B=six D=seven
    • A =" "
    • B= "шесть"
    • C = ""
  3. garbage text A=eight E=nine D=ten B=eleven
    • A = "восьмерка"
    • B = "одиннадцать"
    • C = ""

Первоначально я планировал использовать sed, но с тех пор это не сработаетпорядок «переменных» не согласован (например, последняя строка), а «переменная» может отсутствовать (например, вторая строка).

Моя следующая мысль - проходить строка за строкой,затем разбить строку на поля, используя awk и установить переменные на основе каждого поля, но я понятия не имею, где и как начать.

Я открыт для других идей или лучших предложений.

Ответы [ 7 ]

0 голосов
/ 08 февраля 2019

общая переменная awk, документированная.Предполагая, что разделитель переменных равен = и не является частью текста раньше, ни самого содержимого переменной.

awk 'BEGIN {
        # load the list of variable and order to print
        VarSize = split( "A B C", aIdx )
        # create a pattern filter for variable catch in lines
        for ( Idx in aIdx ) VarEntry = ( VarEntry ? ( VarEntry "|^" ) : "^" ) aIdx[Idx] "="
        }

        {
        # reset varaible value
        split( "", aVar )
        # for each part of the line
        for ( Fld=1; Fld<=NF; Fld++ ) {
           # if part is a varaible assignation
           if( $Fld ~ VarEntry ) {
              # separate variable name and content in array
              split( $Fld, aTemp, /=/ )
              # put variable content in corresponding varaible name container
              aVar[aTemp[1]] = aTemp[2]
              }
           }
        # print all variable content (empty or not) found on this line
        for ( Idx in aIdx ) printf( "%s = \042%s\042\n", aIdx[Idx], aVar[aIdx[Idx]] )
        }
      ' YourFile
0 голосов
/ 08 февраля 2019

Неясно, пытаетесь ли вы установить переменные awk или переменные оболочки, но вот как заполнить ассоциативный массив awk, а затем использовать его для заполнения ассоциативного массива оболочки:

$ cat tst.awk
BEGIN {
    numKeys = split("A B C",keys)
}
{
    delete f
    for (i=1; i<=NF; i++) {
        if ( split($i,t,/=/) == 2 ) {
            f[t[1]] = t[2]
        }
    }
    for (keyNr=1; keyNr<=numKeys; keyNr++) {
        key = keys[keyNr]
        printf "[%s]=\"%s\"%s", key, f[key], (keyNr<numKeys ? OFS : ORS)
    }
}

$ awk -f tst.awk file
[A]="one" [B]="two" [C]="three"
[A]="" [B]="six" [C]=""
[A]="eight" [B]="eleven" [C]=""

$  while IFS= read -r out; do declare -A arr="( $out )"; declare -p arr; done < <(awk -f tst.awk file)
declare -A arr=([A]="one" [B]="two" [C]="three" )
declare -A arr=([A]="" [B]="six" [C]="" )
declare -A arr=([A]="eight" [B]="eleven" [C]="" )

$ echo "${arr["A"]}"
eight
0 голосов
/ 08 февраля 2019

Другой Perl

perl -lne ' %x = /(\S+)=(\S+)/g ; for("A","B","C") { print "$_ = $x{$_}" } %x=() '

с входным файлом

$ perl -lne ' %x = /(\S+)=(\S+)/g ; for("A","B","C") { print "$_ = $x{$_}" } %x=() ' file_test
A = one
B = two
C = three
A =
B = six
C =
A = eight
B = eleven
C =
$
0 голосов
/ 08 февраля 2019

правильный ответ зависит от того, что вы собираетесь делать с переменными.

при условии, что они нужны вам как переменные оболочки, здесь используется другой подход

$ while IFS= read -r line; 
  do A=""; B=""; C=""; 
     source <(echo "$line" | grep -oP "(A|B|C)=\w*" ); 
     echo "A=$A B=$B C=$C"; 
  done < file

A=one B=two C=three
A= B=six C=
A=eight B=eleven C=

, который использует трюкsource для объявлений переменных, извлеченных из каждой строки с grep.Поскольку присвоения значений переносятся, их необходимо сбрасывать перед каждой новой строкой.

0 голосов
/ 08 февраля 2019

Я неравнодушен к решению awk, например,

$ awk '{for (i = 1; i <= NF; i++) if ($i ~ /^[A-Za-z_][^=]*[=]/) print $i}' file
A=one
B=two
C=three
D=four
A=
B=six
D=seven
A=eight
E=nine
D=ten
B=eleven

Объяснение

  • for (i = 1; i <= NF; i++) цикл над каждым разделенным пробелами полем;
  • if ($i ~ /^[A-Za-z_][^=]*[=]/), если поле начинается хотя бы с одного символа, который является [A-Za-z_], за которым следует '=';затем
  • print $i напечатать поле.
0 голосов
/ 08 февраля 2019

Если perl - ваш вариант, попробуйте:

perl -ne 'undef %a; while (/([\w]+)=([\w]*)/g) {$a{$1}=$2;}
    for ("A", "B", "C") {print "$_=\"$a{$_}\"\n";}' file_test

Вывод:

A="one"
B="two"
C="three"
A=""
B="six"
C=""
A="eight"
B="eleven"
C=""

Он анализирует каждую строку для назначений с =, сохраните значение ключапара в массиве ассоциаций %a, затем, наконец, сообщает значения для A, B и C.

0 голосов
/ 08 февраля 2019

В моих первых 3 решениях я считаю, что вам нужно использовать переменные оболочки из значений строк A,B,C, и вы не хотите просто печатать их, если это так, то вам могут помочь следующие (ие).



1-е решение: Он считает, что ваши переменные A,B,C всегда идут с одним и тем же номером поля.

while read first second third fourth fifth sixth
do
  echo $third,$fourth,$fifth        ##Printing values here.
  a_var=${third#*=}
  b_var=${fourth#*=}
  c_var=${fifth#*=}
  echo "Using new values of variables here...."
  echo "NEW A="$a_var
  echo "NEW B="$b_var
  echo "NEW C="$c_var
done < "Input_file"

Это просто печать значений переменных в каждой строке, так как вы НЕ сказали, что вы собираетесь делать с этими переменными, поэтому я просто печатаю их, вы можете использовать их в соответствии с вашим вариантом использования.



2-е решение: Это учитывает, что переменные идут в том же порядке, но проверяет, идет ли A на 3-м месте или нет, B идет на 4-мместо или нет и т. д. и печатает соответственно.

while read first second third fourth fifth sixth
do
  echo $third,$fourth,$fifth        ##Printing values here.
  a_var=$(echo "$third" | awk '$0 ~ /^A/{sub(/.*=/,"");print}')
  b_var=$(echo "$fourth" | awk '$0 ~ /^B/{sub(/.*=/,"");print}')
  c_var=$(echo "$fifth" | awk '$0 ~ /^C/{sub(/.*=/,"");print}')
  echo "Using new values of variables here...."
  echo "NEW A="$a_var
  echo "NEW B="$b_var
  echo "NEW C="$c_var
done < "Input_file"


3-е решение: Что идеально подходит для ваших требований, не уверен, насколько эффективен код тисков (я до сих поранализ больше, если мы могли бы сделать что-то еще здесь).Этот код НЕ будет искать порядок A, B или C в строке, он будет совпадать с ним, пусть они будут где-нибудь в строке, если найдено совпадение, он присвоит значение переменной ИЛИ иначе будет значение NULL.

while read line
do
  a_var=$(echo "$line" | awk 'match($0,/A=[^ ]*/){val=substr($0,RSTART,RLENGTH);sub(/.*=/,"",val);print val}')
  b_var=$(echo "$line" | awk 'match($0,/B=[^ ]*/){val=substr($0,RSTART,RLENGTH);sub(/.*=/,"",val);print val}')
  c_var=$(echo "$line" | awk 'match($0,/C=[^ ]*/){val=substr($0,RSTART,RLENGTH);sub(/.*=/,"",val);print val}')
  echo "Using new values of variables here...."
  echo "NEW A="$a_var
  echo "NEW B="$b_var
  echo "NEW C="$c_var
done < "Input_file

Вывод будет следующим.

Using new values of variables here....
NEW A=one
NEW B=two
NEW C=three
Using new values of variables here....
NEW A=
NEW B=six
NEW C=
Using new values of variables here....
NEW A=eight
NEW B=eleven
NEW C=


EDIT1: В случае, если вы просто хотитечтобы напечатать значения A,B,C, попробуйте следующее.

awk '{
 for(i=1;i<=NF;i++){
   if($i ~ /[ABCabc]=/){
     sub(/.*=/,"",$i)
     a[++count]=$i
   }
 }
 print "A="a[1] ORS "B=" a[2] ORS "C="a[3];count=""
 delete a
}'  Input_file
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...