Bash shell 测试一个字符串中的所有字符是否在另一个字符串中

Bash shell test if all characters in one string are in another string

我有两个字符串,我想比较两个字符串是否相等,字符串必须包含完全相同的字符,但 mychars 可以包含额外的字符。

mychars="abcdefg"
testone="abcdefgh"        # false h is not in mychars
testtwo="abcddabc"        # true all char in testtwo are in mychars

function test() {
    if each char in  is in   # PSEUDO CODE
    then
      return 1
    else
      return 0
    fi
}

if test $testone $mychars; then
   echo "All in the string" ;
else ;  echo "Not all in the string" ; fi

# should echo "Not all in the string" because the h is not in the string mychars

if test $testtwo $mychars; then
   echo "All in the string" ;
else ;  echo "Not all in the string" ; fi

# should echo 'All in the string'

最好的方法是什么?我的猜测是遍历第一个参数中的所有字符。

您可以使用 trmychars 中的任何字符替换为符号,然后您可以测试生成的字符串是否与符号 p.e 有任何不同,:

tr -s "[$mychars]" "." <<< "ggaaabbbcdefg"

输出:

.

但是:

tr -s "[$mychars]" "." <<< "xxxggaaabbbcdefgxxx"

打印:

xxx.xxx

因此,您的函数可能如下所示:

function test() {
    local dictionary=""
    local res=$(tr -s "[$dictionary]" "." <<< "")
    if [ "$res" == "." ]; then 
        return 1
    else
        return 0
    fi
}

更新: 正如 @mklement0 所建议的,整个功能可以通过以下方式缩短(并修复逻辑):

function test() {
    local dictionary=""
    [[ '.' == $(tr -s "[$dictionary]" "." <<< "") ]] 
}

简短、聪明、高效

这里有一个效率较低的替代方案,如果您想知道第一个字符串哪些字符是唯一的,您可能会感兴趣,作为排序的不同列表返回:

charTest() {
  local charsUniqueToStr1
  # Determine which chars. in  aren't in .
  # This returns a sorted, distinct list of chars., each on its own line.
  charsUniqueToStr1=$(comm -23 \
    <(sed 's/\(.\)/\'$'\n''/g' <<<"" | sort -u) \
    <(sed 's/\(.\)/\'$'\n''/g' <<<"" | sort -u))
  # The test succeeds if there are no chars. in  that aren't also in .
  [[ -z $charsUniqueToStr1 ]]
}

mychars="abcdefg" # define reference string

charTest "abcdefgh" "$mychars" 
echo $? # print exit code: 1 - 'h' is not in reference string

charTest "abcddabc" "$mychars"
echo $? # print exit code: 0 - all chars. are in reference string

请注意,我已将 test() 重命名为 charTest() 以避免与 test builtin/utility.

  • sed 's/\(.\)/\'$'\n''/g' 通过将每个字符放在单独的行中,将输入拆分为单个字符。
    • 请注意,该命令在末尾创建了一个额外的空行,但这在本例中无关紧要;要消除它,请将 ; ${s/\n$//;} 附加到 sed 脚本。
    • 该命令以符合 POSIX 的方式编写,这使它变得复杂,因为必须拼接 \-转义的 actual 换行符(通过 ANSI C 引用的字符串,$\n');如果你有 GNU sed,你可以简化为 sed -r 's/(.)/\n/g
  • sort -u 然后对生成的字符列表进行排序并剔除重复项 (-u)。
  • comm -23 比较两个字符串中不同的已排序字符集,并打印出 1st 字符串中唯一的字符(comm 使用 3 列布局, 第一列包含第一个文件独有的行,第二列包含第二列独有的行,第三列打印两个输入文件共有的行;-23 抑制第二列和第三列,实际上只打印第一个输入独有的行)。
  • [[ -z $charsUniqueToStr1 ]] 然后测试 $charsUniqueToStr1 是否为空 (-z);
    换句话说:如果第一个字符串不包含任何字符,则表示成功(退出代码 0)。也没有包含在第二个字符串中;否则,失败(退出代码 1);由于条件 ([[ .. ]]) 是函数中的 last 语句,其退出代码也成为 函数的 退出代码。