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'
最好的方法是什么?我的猜测是遍历第一个参数中的所有字符。
您可以使用 tr
将 mychars
中的任何字符替换为符号,然后您可以测试生成的字符串是否与符号 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 语句,其退出代码也成为 函数的 退出代码。
我有两个字符串,我想比较两个字符串是否相等,字符串必须包含完全相同的字符,但 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'
最好的方法是什么?我的猜测是遍历第一个参数中的所有字符。
您可以使用 tr
将 mychars
中的任何字符替换为符号,然后您可以测试生成的字符串是否与符号 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'
);如果你有 GNUsed
,你可以简化为sed -r 's/(.)/\n/g
- 请注意,该命令在末尾创建了一个额外的空行,但这在本例中无关紧要;要消除它,请将
sort -u
然后对生成的字符列表进行排序并剔除重复项 (-u
)。comm -23
比较两个字符串中不同的已排序字符集,并打印出 1st 字符串中唯一的字符(comm
使用 3 列布局, 第一列包含第一个文件独有的行,第二列包含第二列独有的行,第三列打印两个输入文件共有的行;-23
抑制第二列和第三列,实际上只打印第一个输入独有的行)。[[ -z $charsUniqueToStr1 ]]
然后测试$charsUniqueToStr1
是否为空 (-z
);
换句话说:如果第一个字符串不包含任何字符,则表示成功(退出代码0
)。也没有包含在第二个字符串中;否则,失败(退出代码1
);由于条件 ([[ .. ]]
) 是函数中的 last 语句,其退出代码也成为 函数的 退出代码。