Bash 检查多个数组中是否不存在字符串

Bash 检查多个数组中是否不存在字符串,bash,shell,ksh,Bash,Shell,Ksh,尝试检查字符串值是否不是两个不同数组的成员。如果字符串值在其中任何一个中都不存在,那么我需要执行一条语句。我可以用if语句来做这件事 if [[ $REQ_FIELDS_LIST != *"$XFR_FIELD"* && $NON_INPUT_FIELDS_LIST != *"$XFR_FIELD"* ]];then 但星号会导致子字符串返回误报。不幸的是,删除“*”和if语句根本不起作用。查看这个站点,在bash中执行此操作的唯一安全方法似乎是执行for循环。但是,对于两个不

尝试检查字符串值是否不是两个不同数组的成员。如果字符串值在其中任何一个中都不存在,那么我需要执行一条语句。我可以用if语句来做这件事

if [[ $REQ_FIELDS_LIST != *"$XFR_FIELD"* && $NON_INPUT_FIELDS_LIST != *"$XFR_FIELD"* ]];then
但星号会导致子字符串返回误报。不幸的是,删除“*”和if语句根本不起作用。查看这个站点,在bash中执行此操作的唯一安全方法似乎是执行for循环。但是,对于两个不同的阵列,最有效的方法是什么呢。此外,字符串值是数组本身的成员。所以我们已经在一个数组中循环了。循环遍历字符串值数组,并针对每个字符串值检查该字符串是否不是其他两个数组的成员。如果是,则执行一条语句

所以我需要

for XFR_FIELD in $INPUT_FIELDS_LIST
do
    if XFR field is not a member of REQ_FIELDS_LIST AND is not a member of NON_INPUT_FIELDS_LIST then
        "return 0" 

例如,您可以这样迭代:

#!/bin/bash

INPUT_FIELDS_LIST=( one two three four five)
REQ_FIELDS_LIST=( one six seven eight )
NON_INPUT_FIELDS_LIST=( two three seven eight nine )

for ifl in "${INPUT_FIELDS_LIST[@]}"
do

        for rfl in "${REQ_FIELDS_LIST[@]}"
        do
                myvar=0
                if [[ $ifl == "$rfl" ]]
                then myvar=1; break
                else continue
                fi
        done

        for nifl in "${NON_INPUT_FIELDS_LIST[@]}"
        do
                myvar2=0
                if [[ $ifl == "$nifl" ]]
                then myvar2=1; break
                else continue
                fi
        done

        if [[ $myvar == 1 ]] || [[ $myvar2 == 1 ]]
        then continue
        else echo "$ifl"
        fi

done
手动迭代次循环,然后将其“标记”为无效

末尾的if语句检查两个值是否匹配,如果匹配,则继续下一个主迭代

输出:

four
five

例如,您可以这样迭代:

#!/bin/bash

INPUT_FIELDS_LIST=( one two three four five)
REQ_FIELDS_LIST=( one six seven eight )
NON_INPUT_FIELDS_LIST=( two three seven eight nine )

for ifl in "${INPUT_FIELDS_LIST[@]}"
do

        for rfl in "${REQ_FIELDS_LIST[@]}"
        do
                myvar=0
                if [[ $ifl == "$rfl" ]]
                then myvar=1; break
                else continue
                fi
        done

        for nifl in "${NON_INPUT_FIELDS_LIST[@]}"
        do
                myvar2=0
                if [[ $ifl == "$nifl" ]]
                then myvar2=1; break
                else continue
                fi
        done

        if [[ $myvar == 1 ]] || [[ $myvar2 == 1 ]]
        then continue
        else echo "$ifl"
        fi

done
手动迭代次循环,然后将其“标记”为无效

末尾的if语句检查两个值是否匹配,如果匹配,则继续下一个主迭代

输出:

four
five

有效的方法是使用bash 4.0的关联数组:

#!/usr/bin/env bash
case $BASH_VERSION in ''|[123].*) echo "ERROR: Requires bash 4.0+" >&2; exit 1;; esac

declare -A input_fields_list=( [one]=1 [two]=1 [three]=1 [four]=1 [five]=1 )
declare -A req_fields_list=( [one]=1 [six]=1 [seven]=1 [eight]=1 )
declare -A non_input_fields_list=( [two]=1 [three]=1 [seven]=1 [eight]=1 [nine]=1 )

for xfr in "${!input_fields_list[@]}"; do
  [[ ${req_fields_list[$xfr]} ]] && continue
  [[ ${non_input_fields_list[$xfr]} ]] && continue
  echo "$xfr not found" >&2
  exit 1
done

echo "All input fields are valid" >&2
exit 0

正如您在中所看到的,这正确地存在于
five not found

中。有效的方法是使用bash 4.0的关联数组:

#!/usr/bin/env bash
case $BASH_VERSION in ''|[123].*) echo "ERROR: Requires bash 4.0+" >&2; exit 1;; esac

declare -A input_fields_list=( [one]=1 [two]=1 [three]=1 [four]=1 [five]=1 )
declare -A req_fields_list=( [one]=1 [six]=1 [seven]=1 [eight]=1 )
declare -A non_input_fields_list=( [two]=1 [three]=1 [seven]=1 [eight]=1 [nine]=1 )

for xfr in "${!input_fields_list[@]}"; do
  [[ ${req_fields_list[$xfr]} ]] && continue
  [[ ${non_input_fields_list[$xfr]} ]] && continue
  echo "$xfr not found" >&2
  exit 1
done

echo "All input fields are valid" >&2
exit 0

正如您在中所看到的,如果
five not found

则正确退出。您可以检查一个元素是否在这样的数组中,没有循环,并且不受元素中空格的影响

#! /bin/bash
function elem_in_array() {
    local e="$1"
    shift
    local a=("$@")
    [[ $(printf '\x01%s\x01' "${a[@]}") =~ $(printf '\x01%s\x01' "$e") ]]
}

a1=(A B "C D" E F)
elem_in_array "A" "${a1[@]}" && echo Y || echo N
elem_in_array "B" "${a1[@]}" && echo Y || echo N
elem_in_array "C D" "${a1[@]}" && echo Y || echo N
elem_in_array "AB" "${a1[@]}" && echo Y || echo N

您可以检查元素是否在这样的数组中,没有循环,并且不受元素中空格的影响

#! /bin/bash
function elem_in_array() {
    local e="$1"
    shift
    local a=("$@")
    [[ $(printf '\x01%s\x01' "${a[@]}") =~ $(printf '\x01%s\x01' "$e") ]]
}

a1=(A B "C D" E F)
elem_in_array "A" "${a1[@]}" && echo Y || echo N
elem_in_array "B" "${a1[@]}" && echo Y || echo N
elem_in_array "C D" "${a1[@]}" && echo Y || echo N
elem_in_array "AB" "${a1[@]}" && echo Y || echo N


$REQ\u FIELDS\u LIST&$NON\u INPUT\u FIELDS\u LIST
是数组还是变量?它们被写为变量,但您提到它们是数组。另外-在
$INPUT\u FIELDS\u LIST
中有多少空格或其他分隔值,这是一个数组吗?@BrianGurka如果
REQ\u FIELDS\u LIST
是一个数组,那么
$REQ\u FIELDS\u LIST
仅获取其第一个元素;您需要使用类似于
“$REQ\u FIELDS\u LIST[@]”
的方法来获取所有元素。但这在测试中也不起作用;你真的需要在元素上循环。你考虑过使用关联数组吗?通过这种方式,字符串值可以成为键,成员资格是一个简单的测试。(检查关联数组键成员资格也是一个摊销的常量时间操作,因此它不会随着数组变长而变慢;因此它不仅代码更少,而且速度更快)。这与您的问题无关,但通常应避免使用大写变量名。这是因为
bash
使用了许多大写名称,您可能会与其中一个名称冲突。
$REQ\u FIELDS\u LIST&&$NON\u INPUT\u FIELDS\u LIST
是数组还是变量?它们被写为变量,但您提到它们是数组。另外-在
$INPUT\u FIELDS\u LIST
中有多少空格或其他分隔值,这是一个数组吗?@BrianGurka如果
REQ\u FIELDS\u LIST
是一个数组,那么
$REQ\u FIELDS\u LIST
仅获取其第一个元素;您需要使用类似于
“$REQ\u FIELDS\u LIST[@]”
的方法来获取所有元素。但这在测试中也不起作用;你真的需要在元素上循环。你考虑过使用关联数组吗?通过这种方式,字符串值可以成为键,成员资格是一个简单的测试。(检查关联数组键成员资格也是一个摊销的常量时间操作,因此它不会随着数组变长而变慢;因此它不仅代码更少,而且速度更快)。这与您的问题无关,但通常应避免使用大写变量名。这是因为
bash使用了许多大写名称,您可能会与其中一个名称冲突。
[[]]
将其值解析为C字符串。它不可能尊重NUL文本(而不是,比如说,默默地丢弃它们)。事实上,请参阅位于的stderr日志中的“忽略NUL字节文字”警告(并且命令替换不是免费的——real David Korn ksh93优化了
$(printf…
,使其不使用fork,但bash没有那么聪明);您将看到它发出
BUG
,认为
AB
是内容中存在的字符串。
[[]]]
将其值解析为C字符串。它不可能尊重NUL文本(而不是,比如说,默默地丢弃它们)。事实上,请参阅位于的stderr日志中的“忽略NUL字节文字”警告(并且命令替换不是免费的——real David Korn ksh93优化了
$(printf…
,使其不使用fork,但bash没有那么聪明);您将看到它发出
BUG
,认为
AB
是内容中的字符串。Doh!你赢了我!非常整洁的解决方案,很好地使用了钥匙!为什么在错误输出中输出信息性消息“所有输入字段均有效?”@Bsquare,因为它是一条信息性/日志性消息,这正是stderr的用途(根据POSIX定义)。将日志放在标准输出上会污染输出。shell(没有单独的TTY fd)将提示写入stderr是有原因的,即使这些也不是错误。Doh!你赢了我!非常整洁的解决方案,很好地使用了钥匙!为什么在错误输出中输出信息性消息“所有输入字段均有效?”@Bsquare,因为它是一条信息性/日志性消息,这正是stderr的用途(根据POSIX定义)。把你的日志