LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
楼主: johnny_jiang

实在忍不住了,一直想不通的问题, backslash在$() 和 ``中的不同

[复制链接]
发表于 2006-3-15 22:05:21 | 显示全部楼层
Post by johnny_jiang
最主要是对最后一句的理解:none are treated specially
我是把他理解为一切都按照象处理简单命令那样地处理。如果按照seamonkey兄地解释似乎是解决了我地疑惑,不过在被命令替换后bash又对替换后地内容进行变量替换,这一点好像不太符合bash命令行的解释过程

小弟的理解有可能有所偏差

没有再进行变量替换啊
要是那样的话echo $(echo \$x)的结果就不是$x而是a了
你看看26贴,不知道我有没有表述清楚
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-3-15 23:06:33 | 显示全部楼层
Post by wplxb
总算彻底想通了,呵呵


`command`格式中,“\”被shell处理为转义字符(如果后跟特殊含义字符$,\,`的话),因此`echo \$x`的结果相当于直接在命令行中输入echo $x并回车得到的结果,于是执行echo `echo \$x`得到结果为a(变量x的值)

而$(command)格式中,“\”被shell处理为普通字符,因此$(echo \$x)的结果相当于直接在命令行中输入echo \$x并回车得到的结果,于是执行echo $(echo \$x)得到结果为$x

我觉得命令替换可以理解为将要替换的命令传递给一个子shell执行,然后将得到的结果返回到被替换命令的位置继续执行父shell里的命令。`echo \$x`中,被传递给子shell的实际是echo $x;而$(echo \$x)中被传递给子shell的就是echo \$x


以下这段是引用了置顶贴home_king所写的bash命令行祥解

Post by home_king

1. 将命令行分成由固定元字符集分隔的记号:
SPACE, TAB, NEWLINE, ; , (, ), <, >, |, &
记号类型包括单词,关键字,I/O重定向符和分号。

2.检测每个命令的第一个记号,查看是否为不带引号或反斜线的关键字。如果是一个开放的关键字,如if和其他控制结构起始字符串,function,{或(,则命令实际上为一复合命令。shell在内部对复合命令进行处理,读取下一个命令,并重复这一过程。如果关键字不是复合命令起始字符串(如then等一个控制结构中间出现的关键字),则给出语法错误信号。

3.依据别名列表检查每个命令的第一个关键字。如果找到相应匹配,则替换其别名定义,并退回第一步;否则进入第4步。该策略允许递归别名,还允许定义关键字别名。如alias procedure=function

4.执行大括号扩展,例如a{b,c}变成ab ac

5.如果~位于单词开头,用$HOME替换~。使用usr的主目录替换~user。

6.对任何以符号$开头的表达式执行参数(变量)替换

7.对形式$(string)的表达式进行命令替换
这里是嵌套的命令行处理。

8.计算形式为$((string))的算术表达式

9.把行的参数,命令和算术替换部分再次分成单词,这次它使用$IFS中的字符做分割符而不是步骤1的元字符集。

10.对出现*, ?, [ / ]对执行路径名扩展,也称为通配符扩展

11. 按命令优先级表(跳过别名),进行命令查寻

12.设置完I/O重定向和其他操作后执行该命令。



所以小弟认为命令应该有如下的解释过程

  1. bash# x=a
  2. bash# echo $(echo $x)
  3. 这时的$x是先被当前的bash替换成其值a,如果是在执行子shell时替换的,那么$x应该时空值,所以命令行被解释为
  4. bash# echo $(echo a)
  5. 接着在进行命令替换
  6. bash# a
复制代码


根据上面的替换过程,对于有backslash的情况如下

  1. bash# echo $(echo \$x)
  2. 因为$x被前置了backslash,所以并没有被替换,接着的命令替换过程中,\$x->$x,所以命令就被解释成
  3. bash# echo $x
  4. 因为在命令替换以后只存在arithemetic expansion, word splitting, pattern match, command search and execution。所以这里的$x就被当作普通字符echo出来了
  5. bash# $x
复制代码


以上是小弟的更人想法,因为这个问题感觉很难说清楚,所以小弟就这样写下来,不知道这样的判断过程是否正确,希望各位给予指点:thank
回复 支持 反对

使用道具 举报

发表于 2006-3-16 16:43:46 | 显示全部楼层
Post by wplxb
我倒,说别人误导人之前先自己在命令行实际操作确认一下-_-!


兄弟不要激动,对于命令行替换,我原来也想不通。现在我是这样理解的:命令行替换和本命令是在同一个shell环境下执行的,对于命令行替换,shell又进行了一次命令行处理,包括转义符等等。而$()本身就是设计用来替换``的。bash推荐用$()。保留``只是为了兼容问题。任何软件都有可能有bug.而bash下的$()是严格按命令行处理方式进行命令的处理的,基本上不会有问题,所以我觉得大家不要在这个问题上花时间了。如果两者不一致,那就用$(),以它为准。将时间花在其它更有意义的问题上。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-3-16 22:27:04 | 显示全部楼层
Post by jiazhengw
兄弟不要激动,对于命令行替换,我原来也想不通。现在我是这样理解的:命令行替换和本命令是在同一个shell环境下执行的,对于命令行替换,shell又进行了一次命令行处理,包括转义符等等。而$()本身就是设计用来替换``的。bash推荐用$()。保留``只是为了兼容问题。任何软件都有可能有bug.而bash下的$()是严格按命令行处理方式进行命令的处理的,基本上不会有问题,所以我觉得大家不要在这个问题上花时间了。如果两者不一致,那就用$(),以它为准。将时间花在其它更有意义的问题上。


看来给大家带来了不小的麻烦,呵呵
其实就个人而言,如果没搞清楚,心里会有点别扭
回复 支持 反对

使用道具 举报

发表于 2006-3-17 02:23:16 | 显示全部楼层
the main difference b/w $() and ``is how they process meta char such as "\", Regarding to this, I think it is worthwhile to understand the difference since when you use them with sed/awk, you want to expect the correct result.
btw,
命令行替换和本命令是在同一个shell环境下执行的
is not correct. Command Substitution DOES fork subshell.
  1. echo $(a=1;echo $a); echo $a
复制代码
. If cmd sub is taken place in the parent shell, you would see the second echo prints out 1, but its not.
回复 支持 反对

使用道具 举报

发表于 2006-3-17 08:39:12 | 显示全部楼层
Post by johnny_jiang
以下这段是引用了置顶贴home_king所写的bash命令行祥解



所以小弟认为命令应该有如下的解释过程

  1. bash# x=a
  2. bash# echo $(echo $x)
  3. 这时的$x是先被当前的bash替换成其值a,如果是在执行子shell时替换的,那么$x应该时空值,所以命令行被解释为
  4. bash# echo $(echo a)
  5. 接着在进行命令替换
  6. bash# a
复制代码


根据上面的替换过程,对于有backslash的情况如下

  1. bash# echo $(echo \$x)
  2. 因为$x被前置了backslash,所以并没有被替换,接着的命令替换过程中,\$x->$x,所以命令就被解释成
  3. bash# echo $x
  4. 因为在命令替换以后只存在arithemetic expansion, word splitting, pattern match, command search and execution。所以这里的$x就被当作普通字符echo出来了
  5. bash# $x
复制代码


以上是小弟的更人想法,因为这个问题感觉很难说清楚,所以小弟就这样写下来,不知道这样的判断过程是否正确,希望各位给予指点:thank


子shell继承了父shell的环境
子shell是父shell的子进程,在被创建时复制了父shell的所有资源
见如下命令:

  1. # echo $(a=1;echo $a); echo $a
  2. 1

  3. # echo $a

  4. # a=2;echo $(a=1;echo $a); echo $a
  5. 1
  6. 2
  7. # a=2;echo $(echo $a); echo $a
  8. 2
  9. 2
复制代码
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-3-17 09:36:31 | 显示全部楼层
Yeah, I'm sure that command substitution is executed in subshell.

To yongjian,

Would you please help me to explain how bash interpretes the command below?


  1. bash# x=1
  2. bash# echo `echo \$x`
  3. bash# 1
复制代码


Thank you in advance and look forward to your feedback.
回复 支持 反对

使用道具 举报

发表于 2006-3-17 12:32:56 | 显示全部楼层
I think previous slices explained pretty well. `` treats "\" as a metadata but $() treates it literally, so in subshell, one sees "echo $x" where another sees "echo \$x".
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-3-17 14:50:40 | 显示全部楼层
Post by yongjian
I think previous slices explained pretty well. `` treats "\" as a metadata but $() treates it literally, so in subshell, one sees "echo $x" where another sees "echo \$x".


But why $x is substituted for its value 1, I think '$' should be escaped by '\' in ``.
回复 支持 反对

使用道具 举报

发表于 2006-3-17 23:02:55 | 显示全部楼层
我试了下
  1. echo $(a=1;echo $a); echo $a
复制代码

果然另开了一个subshell执行的。哈哈,看来问题还是要摆出来才行的呀!否则不知就是不知呀!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表