为什么 echo 忽略我的引号字符?

为什么 echo 忽略我的引号字符?

echo命令不包括我提供的完整文本。例如,如果我这样做:

   $ echo ' echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print $2}' `    '

它输出:

echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk {print } `

我的 echo 命令中的单引号 ( ') 不包括在内。如果我切换到双引号:

$ echo " echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print $2}' `  "

echo根本不输出任何东西!为什么它在第一个示例中省略单引号,而在第二个示例中不输出任何内容?如何让它准确输出我输入的内容?

答案1

您的 shell 正在解释引号,包括'",甚至在它们到达 之前echo。我通常只是在我的论点周围加上双引号以回应,即使它们是不必要的;例如:

$ echo "Hello world"
Hello world

因此,在第一个示例中,如果您想在输出中包含文字引号,则需要转义它们:

$ echo \'Hello world\'
'Hello world'

或者它们已经需要在带引号的参数中使用(但不能是同一种引号,否则您无论如何都需要转义它):

$ echo "'Hello world'"
'Hello world'

$ echo '"Hello world"'
"Hello world"

在第二个示例中,您在字符串中间运行命令替换:

grep  $ARG  /var/tmp/setfile  | awk {print $2}

以 开头的内容$也由 shell 专门处理——它将它们视为变量并用它们的值替换它们。由于很可能这些变量都没有在您的 shell 中设置,因此它实际上只是运行

grep /var/tmp/setfile | awk {print}

由于grep只看到一个参数,它假设该参数是您正在搜索的模式,并且它应该从中读取数据的位置是 stdin,因此它会阻止等待输入。这就是为什么你的第二个命令似乎挂起。

如果您单引号参数,则不会发生这种情况(这就是您的第一个示例几乎成功的原因),因此这是获得所需输出的一种方法:

echo \'' echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print $2}' `    '\'

您也可以用双引号将其引起来,但是您需要转义 s,$以便 shell 不会将它们解析为变量,并且需要转义反引号,以便 shell 不会立即运行命令替换:

echo "' echo PARAM=\`  grep  \$ARG  /var/tmp/setfile  | awk '{print \$2}' \`    '"

答案2

我不会详细说明为什么您的尝试会这样做,因为迈克尔·莫罗泽克的回答很好地涵盖了这一点。简而言之,单引号 ( '…') 之间的所有内容均按字面解释(特别是第一个'标记文字字符串的结尾),而`$之间保留其特殊含义"…"

单引号内没有引号,因此不能将单引号放在单引号字符串内。然而,有一个习语看起来像这样:

echo 'foo'\''bar'

这会打印foo'bar,因为 的参数echo由单引号三字符字符串 组成foo,与单个字符(通过前面的'保护字符免受其特殊含义获得)连接,并与单引号三字符字符串 串联。因此,尽管这并不完全是幕后发生的事情,但您可以将其视为在单引号字符串中包含单引号的一种方法。'\bar'\''

如果你想打印复杂的多行字符串,更好的工具是这里的文档。此处文档由两个字符组成<<,后跟一个标记(例如 )<<EOF,然后是一些文本行,最后是该行上单独的结束标记。如果以任何方式引用标记('EOF'"EOF"\EOF或'E""OF'或...),则文本将按字面解释(就像在单引号内一样,除了even'是普通字符)。如果标记根本没有被引用,那么文本将像双引号字符串一样被解释,并$\`保留其特殊状态(但"换行符按字面解释)。

cat <<'EOF'
echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print $2}' `
EOF

答案3

好的,这会起作用:-

echo ' echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '\''{print $2}'\'' `    '

在这里测试它:-

[asmith@yagi ~]$ echo ' echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '\''{print $2}'\'' `    '
 echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print $2}' ` 

答案4

让我们听从您的命令

$ echo ' echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print $2}' `    '

首先将其分割成单词,使用不带引号的空格作为分隔符:

Arg[1]=“' echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print”
Arg[2]=“$2}' `    '”

接下来,我们进行参数扩展:扩展$…但不在内部'…'。由于$2是空的(除非您通过eg设置它set -- …),它将被替换为空字符串。

Arg[1]=“' echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print”
Arg[2]=“}' `    '”

接下来,删除引号。

Arg[1]=“ echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk {print”
Arg[2]=“} `    ”

然后这些参数被传递给 echo,它将逐个打印它们,并用一个空格分隔。

“ echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk {print } `    ”

我希望这个分步说明能够使观察到的行为更加清晰。为了避免这个问题,请像这样转义单引号:

$ echo ' echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '\''{print $2}'\'' `    '

这将结束单引号字符串,然后向单词添加(转义的)单引号,然后开始一个新的单引号字符串,所有这些都不会将单词分开。

相关内容