根据条件在文件上打印行的 shell 脚本

shell script that print lines on a file based on conditions

提问人:Dave Dolone 提问时间:10/31/2023 最后编辑:shellterDave Dolone 更新时间:11/1/2023 访问量:41

问:

我有一个这样的文件

Name: Test1
Acronym: TEST11
Description: null
Toolkit: false
Tracks:

        List:
                Name: 1st_test
                Acronym: TEST11_1
                Created On: 2016-03-22 15:25:27.355
                Created By: User.9
                Is Default: false
                State: State[Inactive]
                Capability: Capability[Standard]
                No of running instances: 0

                Name: 2nd_test
                Acronym: TEST11_2
                Created On: 2016-03-23 15:07:18.955
                Created By: User.9
                Is Default: true
                State: State[Active]
                Capability: Capability[Standard]
                No of running instances: 0

                Name: 3rd_test
                Acronym: TEST11_3
                Created On: 2016-03-22 11:54:45.276
                Created By: User.9
                Is Default: false
                State: State[Inactive]
                Capability: Capability[Standard]
                No of running instances: 1

如果出现以下情况,我需要一个打印首字母缩略词(列表下的脚本)的脚本:

  • line “Is Default” = false
  • 行 “State” = 非活动
  • 行“正在运行的实例数”= 0

从提供的示例文件中,我应该只期望TEST11_1

任何帮助将不胜感激。 问候。

shell if-statement 递归

评论

0赞 Charles Duffy 10/31/2023
我相信我们已经有问答展示了如何使用awk。(并不是说不能在原生 bash 中做到这一点——甚至是原生 POSIX sh,难度更大——但 awk 更容易)。这与递归有什么关系?
0赞 Ulrich Eckhardt 11/1/2023
其中大部分似乎是有效的 YAML,你能验证一下吗?如果是这样,则有用于 YAML 处理的工具。顺便说一句:“shell”不是一种编程语言,而是一整套语言。

答:

1赞 Charles Duffy 10/31/2023 #1
awk -F'[]:[:space:][]+' '
  /^[[:space:]]*$/ {
    if((isDefault == "false") && (instance_count == "0") && (state == "Inactive")) {
        print(acronym)
    }

    acronym=""
    instance_count=0
    isDefault=unknown
    state=unknown
  }
  END {
    if((isDefault == "false") && (instance_count == "0") && (state == "Inactive")) {
        print(acronym)
    }
  }
  /No of running instances:/ { instance_count=$6 }
  /Acronym/ { acronym=$3 }
  /Is Default:/ { isDefault = $4 }
  /State:/ { state=$4 }
'
1赞 Benjamin W. 11/1/2023 #2

由于输入几乎看起来像 YAML,我们可以稍微作弊并将其转换为实际的 YAML,然后使用 yq

sed -E 's/ ( Name:)/-\1/' infile \
    | yq '
      .Tracks.List
      | map(
        select(
          .["Is Default"] | not
          and .State == "State[Inactive]"
          and .["No of running instances"] == 0
        )
        | .Acronym
      )
      | .[]
    '

sed 命令在每个前面加上两个空格,这可能是最脆弱的部分。-Name:

然后,yq 钻取到 ,应用过滤器,映射到 ,然后每行打印一个结果。.Tracks.List.Acronym

评论

0赞 Dave Dolone 11/2/2023
我确定它有效,但我错过了 yq 命令,所以我无法测试它。
0赞 dbran 11/1/2023 #3

有很多方法可以做到这一点。我想到的一个是用来解析文件,然后遍历每个列表段。grep

下面是一个完整的示例:

#!/usr/bin/env bash

shopt -s extglob

# name of the file
file=file.txt

# extract the "Name: ..." lines of file
list_names="$(grep -E '\s+Name' "$file")"

list=()

# add each "Name: ..." line to the "list" array
while IFS= read -r line; do
    # trim string
    list+=("${line##*( )}")
done <<< "$list_names"

# check if all three conditions are met
function check {
    grep --quiet --fixed-strings \
        'Is Default: false' <<< "$1" &&
    grep --quiet --fixed-strings \
        'State: State[Inactive]' <<< "$1" &&
    grep --quiet --fixed-strings \
        'No of running instances: 0' <<< "$1"
}

# loop through each list segment and check
# if conditions are met for each one
for f in "${list[@]}"; do
    # select and store all key/value pairs of each instance
    settings="$(grep -A 7 "$f" "$file")"
    # print "Acronym" value if all three strings
    # are found in the check function
    if check "$settings"; then
        output="$(grep 'Acronym' <<< "$settings")"
        # trim string
        echo "${output##*( )}"
    fi
done

脚本的输出是 ,因为满足所有三个条件。条件在函数中定义。Acronym: TEST11_1TEST11_1check

我不确定这是否足够清楚,因为脚本变得有点冗长。如果您有任何问题,请随时提问。

评论

0赞 Dave Dolone 11/2/2023
这个效果很好。非常