Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在bash中处理分隔行_Bash_Shell_Parsing_Awk - Fatal编程技术网

在bash中处理分隔行

在bash中处理分隔行,bash,shell,parsing,awk,Bash,Shell,Parsing,Awk,给定一行带有空格分隔的'n'参数的输入。输入参数本身是可变的。输入是通过外部文件提供的 我想根据正则表达式将特定元素移动到变量。因此,我想先声明一个指针变量,以跟踪我在行中的位置。此外,变量的赋值与数值顺序无关,根据输入,可能会完全跳过某些变量 我目前的方法是使用 awk'{print$1}'file.txt 然而,并不是所有的元素都是固定的,我需要考虑可能缺少的元素,或者可能有多个条目 更新:我找到了另一种方法 file=$(cat /file.txt) for i in ${file[@]}

给定一行带有空格分隔的'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。通过将每个参数与
*/*

更进一步,var1、var2和var3的输入位置是固定的,但之后我需要进行比较、排序和赋值。此外,参数本身可以在字符长度上有所不同。要划分的每个部分相对于其相邻部分的相对位置是固定的。在输入f中,var7永远不会在var6之前例如,如果var4和var5为真,则第四个和第五个参数将始终为“自动CON”。某些段将始终为一个参数,而其他段则为多个参数。每个段的相对位置都是已知的。对于每个模式,某些段在特定位置具有特定字符,而其他段可能在其po之外没有任何标志按顺序排列

所以我需要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
,但这样做意味着直接将每个参数与每个可能的组合进行比较(并且存在多个段,每个段具有多个模式)是非常不实际的。我试图将此过程分为两个步骤。

更新:此代码多次显示如何基于模式匹配确定变量值。
一个代码块使用纯bash,另一个代码块使用gawk方式

bash代码块需要关联数组支持,这在早期版本中不可用
grep
也需要进行模式匹配
使用
GNUBash,版本4.2.46(2)-发行版(x86_64-redhat-linux-GNU)
grep(GNU-grep)2.20进行测试
学习后,请坚持使用
printf
而不是
echo
在使用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

测试输入

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

请尝试以下操作:

#!/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
!/bin/bash
#变量名模板
declare-a namelist1=(“var1”“var2”“var3”“var4”“var5”“var6”“varC”)
声明-一份声明
#阅读每一行并为元素赋值
读的时候;做的时候
如果[${ary[3]}=AUTO]];则
ary=(“${ary[@]:0:3}”“TRUE”“FALSE”“${ary[4]}”“${ary[@]:5:3}”)
elif[${ary[3]}=CON]];然后
ary=(“${ary[@]:0:3}”“FALSE”“TRUE”“${ary[4]}”“${ary[@]:5:3}”)
其他的
ary=(“${ary[@]:0:3}”“FALSE”“FALSE”“${ary[3]}”“${ary[@]:4:5}”)
fi
#第七元素的初始特征
ary[6]=${ary[7]:0:1}
#在ary中找到*/*项的索引并调整变量名

对于((i=0;我已尝试,但抱歉没有那么清楚,请更清楚地添加示例输出和预期输出示例,以及您需要输出的方式(逻辑).现在应该更清楚了,我希望。据我所知,模式列表应该应用于每一列每一行,并且匹配优先级问题。输入行的顺序和列的内容可能会发生很大变化。请使用示例模式进行更新以匹配给定的输入。旁注:使用awk是可行的,但这是一项相当繁重的工作他关于如何在
awk
这个
awk'{print$$pointer}文件.txt
中使用变量的说明是错误的,不会起作用。我尝试了上述方法,但每次命令都将整个输入视为整行,而不是像我尝试的那样将其拆分。我知道
awk'{print$$pointer}'file.txt
不正确。这是这里的全部问题,如何修复它。我没有设置模式(规则)因为有几十个变量需要检查,每个变量都不同。我不是根据几十个变量检查每个变量,而是尝试将它们全部分开,这样我就可以只根据该变量的相关变量检查每个变量。上面的方法无法很好地处理应完全跳过的特定模式,一个nd其他可能有多个条目需要使用相同规则(varC)进行检查的条目。上述内容也被简化,并且在实际工作中需要处理的变量甚至比上述内容更多。抱歉,我没想到您在一行中有嵌套变量,我将重新考虑处理varC族的代码结构。但是
#!/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