bash sed用法 如何根據條件從數據塊中獲取特定的數據




sed用法 (6)

在這些情況下,記錄中有明確的name = value語句,我喜歡先用這些映射填充一個數組,例如:

map["<name>"] = <value>

然後使用這些名稱來引用我想要的值。 在這種情況下:

$ awk -v RS= -F'\n' '
{
    delete map
    for (i=1;i<=NF;i++) {
        split($i,tmp,/ *= */)
        map[tmp[1]] = tmp[2]
    }
}
map["enable"] !~ /^0$/ {
    print map["name"]
}
' file
blue
orange

如果您的awk版本不支持刪除整個數組,則將delete map更改為split("",map)

與使用RE和/或sub()等相比,如果您想比較和/或打印未來其他字段的值,它使得解決方案更加健壯和可擴展。

我有這樣的文件:

[group]
enable = 0
name =  green
test = more

[group]
name  = blue
test = home

[group]
value = 48
name = orange
test = out

label和=和value之間可能有一個或多個空格/製表符。
每一個區塊的行數可能都很小心。
我喜歡有這個name ,只有當這不是真正的enable = 0

所以輸出應該是:

blue
orange

這是我設法創造的:

awk -v RS="group" '!/enable = 0/ {sub(/.*name[[:blank:]]+=[[:blank:]]+/,x);print $1}'
blue
orange

這有幾個錯誤:

  1. 我無法將RS設置為[group] ,這既失敗RS="[group]"RS="\[group\]" 。 如果name或其他標籤包含group則會失敗。
  2. 我不希望使用多個字符的RS ,因為這只是gnu awk

任何人有其他建議? sedawk而不是使用一長串的命令。


既然你有行分隔記錄,你應該考慮把段落模式的awk 。 如果您必須測試[group]標識符,只需添加代碼來處理。 以下是一些應該滿足您的要求的示例代碼。 運行如下:

awk -f script.awk file.txt

script.awk內容:

BEGIN {

    RS=""
}

{
    for (i=2; i<=NF; i+=3) {

        if ($i == "enable" && $(i+2) == 0) {

            f = 1
        }

        if ($i == "name") {

            r = $(i+2)
        }
    }
}

!(f) && r {

    print r
}

{
    f = 0
    r = ""
}

結果:

blue
orange

如果你不想使用記錄分隔符,你可以使用這樣的虛擬變量:

#!/usr/bin/awk -f

function endgroup() {
   if (e == 1) {
      print n
   }
}

$1 == "name" {
   n = $3
}

$1 == "enable" && $3 == 0 {
  e = 0;
}
$0 == "[group]" {
   endgroup();
   e = 1;
}

END {
   endgroup();
}

如果您知道組總是由空行分隔,請將RS設置為空字符串:

$ awk -v RS="" '!/enable = 0/ {sub(/.*name[[:blank:]]+=[[:blank:]]+/,x);print $1}'
blue
orange

@devnull在他的回答中解釋說,GNU awk也接受RS正則表達式,所以如果它在自己的行上,那麼你只能在[group]分割:

gawk -v RS='(^|\n)[[]group]($|\n)' '!/enable = 0/ {sub(/.*name[[:blank:]]+=[[:blank:]]+/,x);print $1}'

這確保我們不會像邪惡的名字分裂

[group]
enable = 0
name =  [group]
name = evil
test = more

你實際上可以使用Bash。

while read line; do
    if [[ $line == "enable = 0" ]]; then
        n=1
    else
        n=0
    fi
    if [ $n -eq 0 ] && [[ $line =~ name[[:space:]]+=[[:space:]]([a-z]+) ]]; then
        echo ${BASH_REMATCH[1]}
    fi
done < file

這只會工作,但是如果enable = 0總是只有一行上面有name的行。


你的問題似乎是:

我無法將RS設置為[group] ,這既失敗RS="[group]"RS="\[group\]"

他說:

RS="[[]group[]]"

應該產生期望的結果。







awk