Shell脚本中awk匹配制表符异常:命令行有效脚本无效
看起来你遇到的核心问题是脚本中的制表符没有被正确保存为实际的制表符字符,或者awk正则表达式中直接使用制表符的方式不够可靠,结合你的Vim编辑器设置和sed输出,我们来一步步拆解:
为什么命令行有效但脚本失效?
从你用sed 'y/ \t/_$/'的输出可以看到:
⎜___↳_Name_of_my_Device$id=12$[slave__pointer__(2)]
这里的$代表制表符,_代表空格。也就是说:
Name of my Device和id=12之间是制表符id=12和[slave pointer之间也是制表符
在命令行中,你通过Ctrl-V+TAB输入的是真正的制表符字符,所以awk的正则表达式能精准匹配到输出中的制表符。但在Vim中,如果你的编辑器开启了expandtab选项(默认可能开启),你输入的TAB会被自动转换成多个空格,导致脚本里的“制表符”实际上是空格,自然匹配不到xinput输出里的制表符,所以没有输出。
解决方案
这里有几个可靠的解决方法,按推荐程度排序:
1. 在awk正则中用\t表示制表符(最推荐)
不需要手动输入制表符,直接在awk模式中用\t来指代制表符,这样不受编辑器设置影响,兼容性最好:
xinput list | awk '/Name of my Device id[0-9]*\t\[slave pointer/'
2. 关闭Vim的expandtab选项,确保制表符被正确保存
如果你坚持要手动输入制表符,可以在Vim中临时关闭自动转空格的功能:
:set noexpandtab
之后再用Ctrl-V+TAB输入制表符,保存脚本后就能正确识别了。如果想永久生效,可以把set noexpandtab添加到你的~/.vimrc文件中。
3. 使用空白字符类匹配任意空白(灵活兼容)
如果不确定是空格还是制表符,可以用awk支持的POSIX字符类[[:space:]],它能匹配任意空白字符(包括空格、制表符、换行等):
xinput list | awk '/Name of my Device id[0-9]*[[:space:]]\[slave pointer/'
额外验证小技巧
你可以用cat -A命令查看脚本中的字符,确认制表符是否正确保存:
cat -A your_script.sh
如果看到^I,代表是真正的制表符;如果是多个空格,说明被Vim转换成了空格。
内容的提问来源于stack exchange,提问作者Tripp Kinetics

