为何判断日期长度的Shell表达式在Linux正常执行却在Unix报错?
嘿,这个问题我太熟了!本质上就是Linux和Unix的Shell工具链差异在搞鬼,具体来说有两个核心原因:
1. expr length的兼容性坑
Linux上默认用的是GNU版本的expr,它扩展了很多实用功能,length子命令就是其中之一,用来计算字符串长度毫无压力。但很多Unix系统(比如BSD系、传统System V Unix)用的是严格遵循旧POSIX标准的expr,根本没有length这个选项!
当你在Unix上执行expr length $SOME_DATE时,这个命令直接执行失败,输出要么是空字符串,要么是错误信息。这就导致后面的判断语句变成了[ -eq 12 ]——而[(也就是test命令)会把-eq当成一元操作符(比如-z、-n这种只需要一个参数的操作符),但-eq明明是需要左右两个参数的二元操作符,自然就会抛出[: -eq: unary operator expected的错误。
2. Shell语法的严谨性差异(次要但值得注意)
另外,即使expr length能跑,在一些Unix的原生sh里,变量展开如果不加引号,万一变量为空或者包含特殊字符,也会触发类似的参数解析问题。不过你的场景里,主要锅还是expr的兼容性。
给你几个跨平台兼容的解决方案
方案1:用POSIX标准的字符串长度写法(最推荐)
直接用Shell内置的参数展开,这是所有符合POSIX标准的Shell(不管是Linux的bash还是Unix的sh)都支持的写法,完全没兼容性问题,还不用调用外部命令,效率最高:
SOME_DATE=201804132359 if [ ${#SOME_DATE} -eq 12 ]; then echo "日期格式正确" # 这里写你的后续逻辑 fi
${#SOME_DATE}就是获取变量SOME_DATE字符串长度的标准写法,简单粗暴还靠谱。
方案2:如果非要用expr(不推荐,但给你选项)
要是因为某些历史原因必须用expr,可以换用POSIX支持的工具来计算长度,比如wc或者awk:
用wc -c的写法:
SOME_DATE=201804132359 if [ $(echo -n "$SOME_DATE" | wc -c) -eq 12 ]; then echo "日期格式正确" fi
echo -n是为了去掉输出末尾的换行符,避免wc -c多算一个字符。
用awk的写法:
SOME_DATE=201804132359 if [ $(echo "$SOME_DATE" | awk '{print length}') -eq 12 ]; then echo "日期格式正确" fi
不过这两种都需要调用外部命令,不如方案1高效,优先选方案1就好。
内容的提问来源于stack exchange,提问作者JLLMNCHR

