Обработка строки с разделителями в bash - PullRequest
0 голосов
/ 20 сентября 2019

Имеется одна строка ввода с аргументами 'n', разделенными пробелом.Сами входные аргументы являются переменными.Ввод осуществляется через внешний файл.

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

Мой текущий метод заключается в использовании awk '{print $1}' file.txt Однако не все элементы являются фиксированными, и мне нужноучитывать элементы, которые могут отсутствовать или иметь несколько записей.

ОБНОВЛЕНИЕ: я нашел другой метод.

file=$(cat /file.txt)
for i in ${file[@]}; do 
   echo $i >> split.txt; 
done

Таким образом, вместо одной строки с несколькими аргументами, мы получаем несколько строк с одним аргументом.таким образом, теперь мы можем использовать var#=(grep --regexp="[pattern]" split.txt.Теперь мне просто нужно выяснить, как лучше использовать регулярные выражения для фильтрации этого беспорядка.

Позвольте мне привести пример.

Мои входные строки:

RON KKND 1534Z AUTO 253985G 034SRT 134OVC 04/32

RON KKND 5256Z 143623G72K 034OVC 074OVC 134SRT 145PRT 13/00

RON KKND 2234Z CON 342523G CLS 01/M12 RMK

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

var1=RON var2=KKND var3=1534Z var4=TRUE var5=FALSE var6=253985G varC=2 varC1=034SRT varC2=134OVC var7=04/32

var1=RON var2=KKND var3=5256Z var4=FALSE var5=FALSE var6=143623G72K varC=4 varC1=034OVC varC2=074OVC varC3=134SRT varC4=145PRT var7=13/00

var1=RON var2=KKND var3=2234Z var4=FALSE var5=TRUE var6=342523G varC=0  var7=01/M12

Таким образом, четвертый аргумент может быть var4, var5 или var6.Пятый аргумент может быть var5, var6 или соответствовать другому критерию.Шестой аргумент может быть или не быть var6.Между var6 и var7 можно определить, сопоставив каждый аргумент с */*

Сведение этого еще больше, Позиции на входе var1, var2 и var3 фиксированы, но после этого мне нужно сравнить, упорядочить,и назначить.Кроме того, сами аргументы могут различаться по длине символа.Относительная позиция каждой секции, которая будет разделена, фиксирована относительно ее соседей.Например, var7 никогда не будет перед var6 во входных данных, и если var4 и var5 имеют значение true, то 4-й и 5-й аргументы всегда будут «AUTO CON». Некоторые сегменты всегда будут одним аргументом, а другие - более одного.Относительная позиция каждого известна.Что касается каждого шаблона, некоторые из них имеют определенный символ в определенном месте, а другие могут не иметь никакого флага относительно того, что он находится в стороне от своей позиции в последовательности.

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

#Check to see if var4 or var5 exists. if so, flag and increment pointer
pointer=4
if (awk '{print $$pointer}' file.txt) == "AUTO" ; then
   var4="TRUE"
   pointer=$pointer+1
else
   var4="FALSE"
fi
if (awk '{print $$pointer}' file.txt) == "CON" ; then
   var5="TRUE"
   pointer=$pointer+1
else
   var5="FALSE"
fi

#position of var6 is fixed once var4 and var5 are determined
var6=$(awk '{print $$pointer}' file.txt)
pointer=$pointer+1

#Count the arguments between var6 and var7 (there may be up to ten)
#and separate each to decode later. varC[0-9] is always three upcase 
# letters followed by three numbers. Use this counter later when decoding.
varC=0

until (awk '{print $$pointer}' file.txt) == "*/*" ; do

   varC($varC+1)=(awk '{print $$pointer}' file.txt)
   varC=$varC+1
   pointer=$pointer+1
done
#position of var7 is fixed after all arguments of varC are handled
var7=$(awk '{print $$pointer}' file.txt)
pointer=$pointer+1

Я знаю, что приведенный выше синтаксис неверен.Вопрос в том, как это исправить.

var7 не всегда в конце строки ввода.Аргументы после var7, однако, не нужно обрабатывать.

На самом деле интерпретирую шаблоны, к которым я еще не дошел.Я намерен справиться с этим, используя операторы case, сравнивая переменные с регулярными выражениями для сравнения.Я не хочу использовать awk для прямой интерпретации паттернов, так как это может стать очень грязным.Я обдумывал использование for n in $string, но сделать это означало бы сравнение каждого аргумента с каждой возможной комбинацией напрямую (и есть несколько сегментов с несколькими шаблонами), и это нецелесообразно.Я пытаюсь сделать это двухэтапным процессом.

Ответы [ 2 ]

0 голосов
/ 20 сентября 2019

Пожалуйста, попробуйте следующее:

#!/bin/bash

# template for variable names
declare -a namelist1=( "var1" "var2" "var3" "var4" "var5" "var6" "varC" )
declare -a ary

# read each line and assign ary to the elements
while read -r -a ary; do
    if [[ ${ary[3]} = AUTO ]]; then
        ary=( "${ary[@]:0:3}" "TRUE" "FALSE" "${ary[4]}" "" "${ary[@]:5:3}" )
    elif [[ ${ary[3]} = CON ]]; then
        ary=( "${ary[@]:0:3}" "FALSE" "TRUE" "${ary[4]}" "" "${ary[@]:5:3}" )
    else
        ary=( "${ary[@]:0:3}" "FALSE" "FALSE" "${ary[3]}" "" "${ary[@]:4:5}" )
    fi
    # initial character of the 7th element
    ary[6]=${ary[7]:0:1}

    # locate the index of */* entry in the ary and adjust the variable names
    for (( i=0; i<${#ary[@]}; i++ )); do
        if [[ ${ary[$i]} == */* ]]; then
            declare -a namelist=( "${namelist1[@]}" )
            for (( j=1; j<=i-7; j++ )); do
                namelist+=( "$(printf "varC%d" "$j")" )
            done
            namelist+=( "var7" )
        fi
    done

    # assign variables to array elements
    for (( i=0; i<${#ary[@]}; i++ )); do
#       echo -n "${namelist[$i]}=${ary[$i]} "       # for debugging
        declare -n p="${namelist[$i]}"
        p="${ary[$i]}"
    done
#   echo "var1=$var1 var2=$var2 var3=$var3 ..."     # for debugging
done < file.txt

Обратите внимание, что приведенный выше скрипт просто присваивает переменные bash и ничего не печатает, если вы явно не echo или printf переменные.

0 голосов
/ 20 сентября 2019

Обновлено: этот код показывает, как определять значение переменной на основе сопоставления с шаблоном несколько раз.
один блок кода в чистом bash, а другой - в режиме gawk

блок кода bash требует поддержки ассоциативного массива,который недоступен в очень ранних версиях
grep, также требуется выполнить сопоставление с шаблоном
, протестированное с GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu) и grep (GNU grep) 2.20, и придерживаться printf, отличного от echo после того, как я изучу Why-is-printf-лучше-чем-эхо
при использовании bash я считаю хорошей практикой быть более оборонительным

#!/bin/bash
declare -ga outVars
declare -ga lineBuf
declare -g NF
#force valid index starts from 1
#consistent with var* name pattern
outVars=(unused var1 var2 var3 var4 var5 var6 varC var7)
((numVars=${#outVars[@]} - 1))
declare -gr numVars
declare -r outVars

function e_unused {
    return
}
function e_var1 {
    printf "%s"  "${lineBuf[1]}"
}
function e_var2 {
    printf "%s"  "${lineBuf[2]}"
}
function e_var3 {
    printf "%s"  "${lineBuf[3]}"
}

function e_var4 {
    if [ "${lineBuf[4]}" == "AUTO" ] ;
    then
        printf "TRUE"
    else
        printf "FALSE"
    fi
}
function e_var5 {
    if [ "${lineBuf[4]}" == "CON" ] ;
    then
        printf "TRUE"
    else
        printf "FALSE"
    fi
}
function e_varC {
    local var6_idx=4
    if [ "${lineBuf[4]}" == "AUTO" -o "${lineBuf[4]}" == "CON" ] ;
        then
            var6_idx=5
    fi

    local var7_idx=$NF
    local i
    local count=0
    for ((i=NF;i>=1;i--));
    do
        if [ $(grep -cE '^.*/.*$' <<<${lineBuf[$i]}) -eq 1 ];
            then
            var7_idx=$i
            break
        fi
    done
    ((varC = var7_idx - var6_idx - 1))
    if [ $varC -eq 0 ];
        then
        printf 0
        return;
    fi
    local cFamily=""
    local append
    for ((i=var6_idx;i<=var7_idx;i++));
    do
        if [ $(grep -cE '^[0-9]{3}[A-Z]{3}$' <<<${lineBuf[$i]}) -eq 1 ];
            then
            ((count++))
            cFamily="$cFamily varC$count=${lineBuf[$i]}"
        fi
    done
    printf "%s %s"  $count "$cFamily"
}

function e_var6 {
    if [ "${lineBuf[4]}" == "AUTO" -o "${lineBuf[4]}" == "CON" ] ;
        then
        printf "%s"  "${lineBuf[5]}"
    else
        printf "%s"  "${lineBuf[4]}"
    fi
}
function e_var7 {
    local i
    for ((i=NF;i>=1;i--));
    do
        if [ $(grep -cE '^.*/.*$' <<<${lineBuf[$i]}) -eq 1 ];
            then
            printf "%s"  "${lineBuf[$i]}"
            return
        fi
    done
}

while read  -a lineBuf ;
    do
    NF=${#lineBuf[@]}
    lineBuf=(unused ${lineBuf[@]})
    for ((i=1; i<=numVars; i++));
        do
        printf "%s="  "${outVars[$i]}"
        (e_${outVars[$i]})
        printf " "
    done
    printf "\n"

done <file.txt

Расширение, специфичное для gawk Косвенный вызов функции используется в приведенном ниже коде awk
код назначает имя функции для каждой требуемой выходной переменной.
другой шаблон или другое преобразование можно применять в его конкретной функции
, делая это, чтобы избежать тонн if-else-if-else
, а также легче читать и расширять.
для специального семейства varC, функция pick_varC сыграла свою роль
после определения varC, ее значениесостоит из нескольких выходных полей.
, если varC=2, значение varC возвращается как 2 varC1=034SRT varC2=134OVC
, которое является фактическим значением varC, добавляя все последующие члены.

gawk '
    BEGIN {
        keys["var1"] = "pick_var1";
        keys["var2"] = "pick_var2";
        keys["var3"] = "pick_var3";
        keys["var4"] = "pick_var4";
        keys["var5"] = "pick_var5";
        keys["var6"] = "pick_var6";
        keys["varC"] = "pick_varC";
        keys["var7"] = "pick_var7";
    }

    function pick_var1 () {
        return $1;
    }
    function pick_var2 () {
        return $2;
    }
    function pick_var3 () {
        return $3;
    }

    function pick_var4 () {
        for (i=1;i<=NF;i++) {
            if ($i == "AUTO") {
                return "TRUE";
            }
        }
        return "FALSE";
    }

    function pick_var5 () {
        for (i=1;i<=NF;i++) {
            if ($i == "CON") {
                return "TRUE";
            }
        }
        return "FALSE";
    }

    function pick_varC () {
        for (i=1;i<=NF;i++) {
            if (($i=="AUTO" || $i=="CON")) {
                break;
            }
        }
        var6_idx = 5;
        if ( i!=4 ) {
            var6_idx = 4;
        }
        var7_idx = NF;
        for (i=1;i<=NF;i++) {
            if ($i~/.*\/.*/) {
                var7_idx = i;
            }
        }
        varC = var7_idx - var6_idx - 1;
        if ( varC == 0) {
            return varC;
        }
        count = 0;
        cFamily = "";
        for (i = 1; i<=varC;i++) {
            if ($(var6_idx+i)~/[0-9]{3}[A-Z]{3}/) {
                cFamily = sprintf("%s varC%d=%s",cFamily,i,$(var6_idx+i));
                count++;
            }
        }
        varC = sprintf("%d %s",count,cFamily);
        return varC;
    }

    function pick_var6 () {
        for (i=1;i<=NF;i++) {
            if (($i=="AUTO" || $i=="CON")) {
                break;
            }
        }
        if ( i!=4 ) {
            return $4;
        } else {
            return $5
        }
    }

    function pick_var7 () {
        for (i=1;i<=NF;i++) {
            if ($i~/.*\/.*/) {
                return $i;
            }
        }
    }

    {
        for (k in keys) {
            pickFunc = keys[k];
            printf("%s=%s ",k,@pickFunc());
        }
        printf("\n");
    }
    ' file.txt

тестовый ввод

RON KKND 1534Z AUTO 253985G 034SRT 134OVC 04/32
RON KKND 5256Z 143623G72K 034OVC 074OVC 134SRT 145PRT 13/00
RON KKND 2234Z CON 342523G CLS 01/M12 RMK

вывод сценария

var1=RON var2=KKND var3=1534Z var4=TRUE var5=FALSE varC=2  varC1=034SRT varC2=134OVC var6=253985G var7=04/32
var1=RON var2=KKND var3=5256Z var4=FALSE var5=FALSE varC=4  varC1=034OVC varC2=074OVC varC3=134SRT varC4=145PRT var6=143623G72K var7=13/00
var1=RON var2=KKND var3=2234Z var4=FALSE var5=TRUE varC=0  var6=342523G var7=01/M12
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...