shell中eval的神奇之法,shell中引号的争端
2016-04-18 21:48
501 查看
话说大家都知道,shell中的变量是等价替换的。例如下面这个例子:
上面这个结果就是表示给变量cmd赋值为ls -lrt ,然后直接使用变量就相当于执行了ls -lrt
因此在shell脚本中当然也可以这么写,例如:
运行结果:
接下来我们看一个命令:
su - jeremysong -c "(pwd;. /media/jeremysong/document/test/source.sh;ls -lrt)"
它的直接结果如下:
然后我们写两个脚本,source.sh和runner.sh
然而就在我们运行runner.sh的时候,情况出现了:
纳尼?! 为什么报错了?shell不是变量替换么,单独运行哪一行一点问题都没有,这是为什么?好,那么我们用调试模式看一下:
好吧,我们现在确认了是上面圈出来的那句出错了,那么这个能否正常执行呢?
答案肯定是不行的。
因为shell中的双引号和单引号虽然都可以表示字符串,但是两者还有差别的。
单引号用于保持引号内所有字符的字面值,即使引号内的\和回车也不例外,但是字符串中不能出现单引号。(注意是所有,只是单引号本身不能够出现在其中)。
双引号用于保持引号内所有字符的字面值(回车也不例外),但以下情况除外:
$加变量名可以取变量的值
反引号仍表示命令替换
\$表示$的字面值
\`表示`的字面值
\"表示"的字面值
\\表示\的字面值
除以上情况之外,在其它字符前面的\无特殊含义,只表示字面值。
下面看个例子:
可见,单引号中完全是保持字符串的原型输出,而双引号进行了命令替换。
所以我们可以修改runner.sh脚本成如下的写法:
<span style="font-family:Microsoft YaHei;font-size:12px;">#!/bin/bash
function run()
{
echo "------------------runner-----------START-------------"
cmd="su - jeremysong -c \"(pwd;. /media/jeremysong/document/test/source.sh;ls -lrt)\""
eval $cmd
echo "------------------runner------------END--------------"
}
run $@
</span>我们在看看运行结果:
运行结果完全没问题。那么为何eval命令可以解决这个问题呢?
答案是,eval命令将会首先扫描命令行进行所有的置换,然后再执行该命令。该命令适用于那些一次扫描无法实现其功能的变量,就像我们刚才那样写的例子。
eval命令对变量进行两次扫描。这些需要进行两次扫描的变量有时被称为复杂变量。不过这些变量本身并不复杂。eval命令也可以用于回显简单变量,不一定是复杂变量。
那么,好了。这里要说的也就是怎么来处理问题了。如果读者对于shell中的单引号和双引号之间的差异,以及eval命令想要更进一步了解的话,可以多查查资料熟悉熟悉,这里就不一一介绍了。
知识点:
shell中单引号和双引号的区别
shell脚本的调试
shell命令eval
上面这个结果就是表示给变量cmd赋值为ls -lrt ,然后直接使用变量就相当于执行了ls -lrt
因此在shell脚本中当然也可以这么写,例如:
<span style="font-family:Microsoft YaHei;font-size:12px;">#!/bin/bash function main() { cmd="pwd" $cmd } main $@ </span>
运行结果:
接下来我们看一个命令:
su - jeremysong -c "(pwd;. /media/jeremysong/document/test/source.sh;ls -lrt)"
它的直接结果如下:
然后我们写两个脚本,source.sh和runner.sh
<span style="font-family:Microsoft YaHei;font-size:12px;">#!/bin/bash export DEVICE="Thinkpad SL410" export OS="Ubuntu" function print_time() { date } function main() { print_time } main $@ </span>
<span style="font-family:Microsoft YaHei;font-size:12px;">#!/bin/bash function run() { echo "------------------runner-----------START-------------" cmd="su - jeremysong -c \"(pwd;. /media/jeremysong/document/test/source.sh;ls -lrt)\"" ${cmd} echo "------------------runner------------END--------------" } run $@ </span>
然而就在我们运行runner.sh的时候,情况出现了:
纳尼?! 为什么报错了?shell不是变量替换么,单独运行哪一行一点问题都没有,这是为什么?好,那么我们用调试模式看一下:
好吧,我们现在确认了是上面圈出来的那句出错了,那么这个能否正常执行呢?
答案肯定是不行的。
因为shell中的双引号和单引号虽然都可以表示字符串,但是两者还有差别的。
单引号用于保持引号内所有字符的字面值,即使引号内的\和回车也不例外,但是字符串中不能出现单引号。(注意是所有,只是单引号本身不能够出现在其中)。
双引号用于保持引号内所有字符的字面值(回车也不例外),但以下情况除外:
$加变量名可以取变量的值
反引号仍表示命令替换
\$表示$的字面值
\`表示`的字面值
\"表示"的字面值
\\表示\的字面值
除以上情况之外,在其它字符前面的\无特殊含义,只表示字面值。
下面看个例子:
可见,单引号中完全是保持字符串的原型输出,而双引号进行了命令替换。
所以我们可以修改runner.sh脚本成如下的写法:
<span style="font-family:Microsoft YaHei;font-size:12px;">#!/bin/bash
function run()
{
echo "------------------runner-----------START-------------"
cmd="su - jeremysong -c \"(pwd;. /media/jeremysong/document/test/source.sh;ls -lrt)\""
eval $cmd
echo "------------------runner------------END--------------"
}
run $@
</span>我们在看看运行结果:
运行结果完全没问题。那么为何eval命令可以解决这个问题呢?
答案是,eval命令将会首先扫描命令行进行所有的置换,然后再执行该命令。该命令适用于那些一次扫描无法实现其功能的变量,就像我们刚才那样写的例子。
eval命令对变量进行两次扫描。这些需要进行两次扫描的变量有时被称为复杂变量。不过这些变量本身并不复杂。eval命令也可以用于回显简单变量,不一定是复杂变量。
那么,好了。这里要说的也就是怎么来处理问题了。如果读者对于shell中的单引号和双引号之间的差异,以及eval命令想要更进一步了解的话,可以多查查资料熟悉熟悉,这里就不一一介绍了。
知识点:
shell中单引号和双引号的区别
shell脚本的调试
shell命令eval
相关文章推荐
- android wifi 无线调试
- 运维入门
- 神器SystemTap
- 动态清空 nohup 输出文件
- install scrapy with pip and easy_install
- Linux Shell常用技巧
- Shell 脚本编程陷阱
- Python 七步捉虫法
- shell字符串操作详解
- Lua编程示例(一):select、debug、可变参数、table操作、error
- Shell中删除某些文件外所有文件的3个方法
- Ruby中执行Linux shell命令的六种方法详解
- VB使用shell函数打开外部exe程序的实现方法
- Shell编程的一些知识集合
- Shell中的for和while循环详细总结
- 什么是Shell?Shell脚本基础知识详细介绍
- Shell脚本中引用、调用另一个脚本文件的2种方法
- C#中的两种debug方法介绍
- Shell脚本解压rpm软件包
- Linux Shell 数组建立及使用技巧