我有一个名为的文件,fileWithOneCommand.txt
仅用以下命令命名,如下所示
ps -aux|head -n 5
然后我编写了一个名为'test5.sh'的测试shell脚本,内容如下:
file=/home/somepath/fileWithOneCommand.txt
$file;
echo see;
cat $file;
echo see2;
$(cat $file);
echo see3;
但我无法理解结果,结果如下:
$ ./test5.sh
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 168584 10308 ? Ss Feb19 0:49 /sbin/init splash
root 2 0.0 0.0 0 0 ? S Feb19 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? S Feb19 0:00 [pool_workqueue_release]
root 4 0.0 0.0 0 0 ? I< Feb19 0:00 [kworker/R-rcu_g]
see
ps -aux|head -n 5
see2
error: user name does not exist
Usage:
ps [options]
Try 'ps --help <simple|list|output|threads|misc|all>'
or 'ps --help <s|l|o|t|m|a>'
for additional help text.
For more details see ps(1).
see3
$file应该显示变量文件的内容,所以应该输出,
ps -aux|head -n 5
但为什么输出的是ps -aux|head -n 5的执行结果,而不是只显示ps -aux|head -n 5?cat $file; 返回 ps -aux|head -n 5,但是为什么
$(cat $file);
返回错误“错误:用户名不存在”?
当我在谷歌上搜索命令替换时,它说“命令的输出替换了命令本身。 Shell 通过执行命令然后用命令的标准输出替换命令替换来操作扩展。”
所以对于
$(cat $file);
括号里面,cat $file 返回 ps -aux|head -n 5 那么为什么$(cat $file);不返回 ps -aux|head -n 5 的执行结果,而是返回错误“error:用户名不存在”呢?
shell 扩展的结果(无论是 $() 还是 $variable 甚至是反引号命令替换)不会经过“完整”的 shell 输入解析 - 只会进行单词拆分(我认为是通配符扩展)。在这个特定的例子中,如果结果包含
|
,它将不会被解析为管道运算符 - 它将保留为文字“|”。因此,整个扩展结果不再是两个命令
ps -aux
和,而是带有 3 个参数的单个命令:。head -n 5
ps -aux|head -n 5
"ps"
"-aux|head"
"-n"
"5"
Linux
ps
试图结合两种截然不同的命令行样式(BSD 和 SysV),并且同一个选项可能意味着两到三种不同的东西,具体取决于哪个“模式”ps
猜测。例如,BSD 有-u
,但 SysV 却有-u <username>
,它的作用不同。在这种情况下,它首先尝试将第一个参数解释为 BSD 样式的选项
-a
-u
-x
-|
...,但由于选项-|
不存在,程序切换到 SysV 样式并-u
接受一个参数。因此,其余部分
x|head
成为 SysV 选项的“用户名”参数-u
,并且由于您的系统上不存在这样的用户帐户,因此您会收到错误消息。要强制完整解析字符串,您需要这样做
eval
。例如,eval "$mycmd"
或eval "$(cat $myfile)"
- 尽管后者最好写为. $myfile
或source $myfile
。该
~/bin/args
工具(bash 和 C 变体):