为什么shell忽略通过变量传递给它的参数中的引号?

为什么shell忽略通过变量传递给它的参数中的引号?

这项工作如广告所示:

# example 1#!/bin/bashgrep -ir 'hello world' .

这并不是:

# example 2#!/bin/bashargumentString="-ir 'hello world'"grep $argumentString .

尽管'hello world'在第二个示例中用引号括起来,grep解释'hello作为一个论点world'作为另一种,这意味着,在这种情况下,'hello将是搜索模式world'将是搜索路径。

同样,只有当参数从argumentString变量。grep正确解释'hello world'作为第一个例子中的一个参数。

有人能解释一下为什么吗?是否有适当的方法来展开字符串变量,以保留每个字符的语法,从而使其被shell命令正确地解释?


守着星空守着你
浏览 1196回答 3
3回答

胡说叔叔

为什么当字符串被展开时,它被分割成单词,但是它不会被重新计算以找到特殊的字符,如引号或美元符号或.这是壳牌自1978年伯恩壳牌(Bourne Shell)前后一直表现出来的方式。固定在……里面bash,使用数组保存参数:argumentArray=(-ir 'hello world')grep "${argumentArray[@]}" .或者,如果勇敢/鲁莽,就用eval:argumentString="-ir 'hello world'"eval "grep $argumentString ."另一方面,谨慎常常是勇气的更好的部分,并与之合作。eval是一个谨慎胜于勇敢的地方。如果没有完全控制字符串,则为evalid(如果命令字符串中有任何用户输入未经严格验证),那么您将面临潜在的严重问题。请注意,Bash的展开顺序在壳展开在GNU手册里。请特别注意3.5.3 Shell参数展开、3.5.7字拆分和3.5.9引号删除部分。

不负相思意

在查看这个问题和相关问题时,我感到惊讶的是,没有人使用显式的子shell。对于bash和其他现代shell,可以显式执行命令行。在bash中,它需要-c选项。argumentString="-ir 'hello world'"bash -c "grep $argumentString ."完全符合发问者的要求。这种技术有两个限制:只能在命令或参数字符串中使用单引号。命令只有导出的环境变量可用。此外,这种技术处理重定向和管道,以及其他搁置工作。您还可以使用bash内部命令以及在命令行中工作的任何其他命令,因为您实际上是要求subshell bash将其直接解释为命令行。这里有一个更复杂的例子,一个有点毫无道理的复杂的ls-l变体。cmd="prefix=`pwd` && ls | xargs -n 1 echo \'In $prefix:\'"bash -c "$cmd"我已经用这种方式和参数数组构建了命令处理器。一般来说,这种方式是多编写和调试更容易,而且响应正在执行的命令也很简单。OTOH,Param数组在您确实有抽象的参数数组时工作得很好,而不是只想要一个简单的命令变体。
打开App,查看更多内容
随时随地看视频慕课网APP