Linux - C SHELL报错提示"Missing }."
问题描述
Last login: Mon Aug 9 20:07:43 2021
Welcome to Alibaba Cloud Elastic Compute Service !
[thesre@centos8 ~]$ source .cshrc
Missing }.
[thesre@centos8 ~]$
问题分析
为了便于演示,本案例将二分法定位故障域、source(间接)语句以及其余无关语句都移除。
将.cshrc
文件备份,source备份文件。第一次无报错,第二次source时会报错,如下
[thesre@centos8 ~]$ mv .cshrc .cshrc_bak20210809
[thesre@centos8 ~]$ exit #exit and log in again.
Last login: Mon Aug 9 20:09:09 2021 from 219.134.115.231
Welcome to Alibaba Cloud Elastic Compute Service !
[thesre@centos8 ~]$ source .cshrc_bak20210809 #第一次无报错
[thesre@centos8 ~]$ source .cshrc_bak20210809 #第二次报错
Missing }.
[thesre@centos8 ~]$
查看.cshrc文件
[thesre@centos8 ~]$ cat .cshrc_bak20210809
set set_result=`set|grep ^set`
alias grep 'grep -r'
使用简单的二分排除法,
注释第一行:
[thesre@centos8 ~]$ cat .cshrc_bak20210809
# set set_result=`set|grep ^set`
alias grep 'grep -r'
[thesre@centos8 ~]$ source .cshrc_bak20210809 #第一次无报错
[thesre@centos8 ~]$ source .cshrc_bak20210809 #第二次无报错
注释第二行:
[thesre@centos8 ~]$ cat .cshrc_bak20210809
set set_result=`set|grep ^set`
# alias grep 'grep -r'
[thesre@centos8 ~]$ source .cshrc_bak20210809 #第一次无报错
[thesre@centos8 ~]$ source .cshrc_bak20210809 #第二次无报错
观察到上述任何一行单独存在时,都无报错。
我们仔细分析下这两句命令,第一句看起来没什么特别,执行set然后过滤一下以set开头的字符串。第二句我们看下,是设置grep别名,默认加上-r选项。
[thesre@centos8 ~]$ man grep
-r, --recursive
Read all files under each directory, recursively, following symbolic links only if they are on the command line. This is equivalent to the -d recurse option.
在ssh登陆进来后,被第二遍source时该grep别名是生效的。由于CWD为家目录,
set set_result=`set|grep ^set`
命令就会从家目录递归地过滤,并将结果赋值给set_result
。我们将这两句放到一个脚本,并在解析器那一行加上-x
选项,打开调试模式:
[thesre@centos8 ~]$ cat debug_missing_closing_curly_brace.csh
#!/bin/csh -x
alias grep 'grep -r'
set set_result=`set|grep ^set`
[thesre@centos8 ~]$ ./debug_missing_closing_curly_brace.csh
alias grep grep -r
set set_result=`set|grep ^set`
grep -r ^set
set
Missing }.
可以看到是执行set命令时报了错。
错误解决
经确认,该别名是错误设置的,因为一般情况下都不会默认使用当前文件夹来递归过滤字符串。将该别名去掉即可解决问题。
知识延伸
在这里复现一种引起Missing }
报错的场景。定义一个变量,赋值字符串,然后使用echo打印它。
[ben@centos8 ~]$ set set_result='{"key01":"", "key02":""}'
[ben@centos8 ~]$ echo $set_result
Missing }.
根据资料,可以使用variable modifier来打印变量的值。
5.3.2 Variable Modifiers Except for $? var , $$ , $?0 , and $< , the variable substitutions above may be followed by one of these modifiers. When braces are used, the modifier goes inside them. docstore.mik.ua/orelly/unix/unixnut/ch05_03.htm
:q Quote a wordlist variable, keeping the items separate. Useful when the variable contains filename metacharacters that should not be expanded. docstore.mik.ua/orelly/unix/unixnut/ch05_03.htm
效果:
[ben@centos8 ~]$ set set_result='{"key01":"", "key02":""}'
[ben@centos8 ~]$ echo $set_result
Missing }.
[ben@centos8 ~]$ echo $set_result:q
{"key01":"", "key02":""}
心得
在定位时,经常会遇到这样的情况:在第一次source时正常,第二次source时却报错。这个时候应该朝“两个或两个语句以上综合引起报错”的方向定位,因为很明显,第一次source不会报错。
参考资料
https://docstore.mik.ua/orelly/unix/unixnut/ch05_03.htm