如何在POSIX sh中判断字符串是否以"!"开头
!开头的方法 在POSIX兼容的sh环境下(注意不是bash哦),我们没法用bash专属的字符串切片语法,得用标准内置工具或命令来实现判断逻辑。下面给你两种可靠的实现方式,覆盖单个字符串判断和逐行检测的场景:
一、判断单个字符串是否以!开头
方法1:用内置case语句(推荐,无外部依赖)
case是POSIX sh的内置命令,模式匹配非常可靠,而且不需要调用外部工具,性能更好。示例代码:
# 定义测试字符串 test_str="!hello world" case "$test_str" in !*) echo "字符串以!开头" ;; *) echo "字符串不以!开头" ;; esac
解释:!*是POSIX的通配符模式,!匹配开头的感叹号,*匹配后续任意字符。记得把变量用双引号括起来,避免空字符串或者包含空格/特殊字符的字符串出现意外行为。
方法2:用expr命令(POSIX标准工具)
expr是POSIX规定的标准工具,支持基于正则的开头匹配。我们可以利用它的退出码来判断:
test_str="regular text" if expr "$test_str" : '!' > /dev/null; then echo "字符串以!开头" else echo "字符串不以!开头" fi
解释:expr "$str" : '!'会尝试匹配字符串的开头是否为!,匹配成功返回1(匹配的字符数),失败返回0。我们把输出重定向到/dev/null,只关心它的退出码(成功时退出码为0,失败为1)。
二、检测行内容是否以!开头
如果需要处理文件或标准输入中的每一行,判断是否以!开头,可以结合上面的方法和while循环,或者用grep快速过滤:
方法1:逐行读取判断(脚本内处理)
用IFS= read -r来正确读取每行内容(保留空格、制表符,不转义反斜杠),再用case判断:
# 读取input.txt文件的每一行 while IFS= read -r line; do case "$line" in !*) echo "匹配行: $line" ;; # 不需要处理非匹配行的话,可以删掉下面的分支 *) echo "非匹配行: $line" ;; esac done < input.txt
如果是从标准输入读取(比如管道输入),把< input.txt去掉即可,比如cat input.txt | while IFS= read -r line; do ... done。
方法2:用grep快速过滤(适合命令行或简单脚本)
grep是POSIX标准工具,用行首锚点^匹配开头的!:
# 过滤出input.txt中以!开头的行 grep '^!' input.txt
解释:^在POSIX基本正则表达式中表示行的起始位置,!是普通字符,不需要转义,所以^!就能精准匹配以!开头的行。
小提示
所有示例都严格遵循POSIX sh标准,在dash、ash等纯sh环境下都能正常运行,不要使用bash专属的${test_str:0:1}这种字符串切片语法,因为POSIX sh不支持扩展的参数展开。
内容的提问来源于stack exchange,提问作者Scott Stamile

