我需要编写一个 bash 脚本,它将在 Android 设备上执行。除其他外,我需要这个脚本来计算字符串中特定字符的出现次数,因为 wc
(字数统计)实用程序在 Android shell 中不可用,我这样做是这样的:
my_string="oneX two threeX"; x_amount="${my_string//[^X]}"; echo $x_amount; echo "${#x_amount}"
当我在桌面上运行上述命令时,它返回(正如我所期望的):
XX
2
但如果我在我的 Android 设备上执行相同的命令(通过 adb shell
),令我惊讶的是,结果是:
one two three
13
我发现(只是猜测)如果我将 !
替换为 ^
,那么该命令将变为:
my_string="oneX two threeX"; x_amount="${my_string//[!X]}"; echo $x_amount; echo "${#x_amount}";
然后,在 Android 上,它会产生我期望的结果:
XX
2
虽然同一命令在桌面上失败并显示以下消息:
event not found: X]
尽管我已经弄清楚如何“让它工作”,但我想了解以下几点:
除了 Android shell,还有什么地方使用了
[!X]
表示法,而不是[^X]
?这种表示法有什么特殊的名称吗?
Android 不支持
[^X]
有什么具体原因吗?
P.S.:我需要在其上运行脚本的设备有相当旧的 Android 版本 (4.4),所以这个“问题”可能是特定于 Android 版本的,即使是这种情况,问题以上保留。
最佳答案
Android 的外壳是 mksh
, witch 使用与 Bash 不同的 RegEx 或模式方言。
参见:
File name patterns在 mksh
's man-page :
File name patterns ... [!...] Like [...], except it matches any octet not inside the brackets.
让我们用字符串替换和负字符类模式 [!...]
语法测试一些 shell 兼容性:
#!/usr/bin/env bash
shells=( ash bash dash ksh93 mksh tcsh zsh )
compat=()
not_compat=()
for shell in "${shells[@]}"; do
if [ "$(
"$shell" <<'EOF' 2>/dev/null
my_string="oneX two threeX"
x_amount="${my_string//[!X]}"; echo "$x_amount${#x_amount}"
EOF
)" = "XX2" ]; then
compat+=("$shell")
else
not_compat+=("$shell")
fi
done
echo "Shells that understands the [!...] negative class syntax:"
printf '%s\n' "${compat[@]}"
echo
echo "Shells that don't understand string substitution:"
printf '%s\n' "${not_compat[@]}"
输出:
Shells that understands the [!...] negative class syntax:
bash
ksh93
mksh
zsh
Shells that don't understand string substitution:
ash
dash
tcsh
另请注意 sed
不理解 POSIX 否定字符组表示法 [!...]
,即使禁用其 Gnu 扩展也是如此:
sed --posix 's/[!X]//g' <<<'oneX two threeX'
one two three
但是
sed --posix 's/[^X]//g' <<<'oneX two threeX'
XX
关于android - 为什么 Android 的 "not the following character"正则表达式是 [!x] 而不是 [^x]?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57545437/