Bash 究竟为什么result=$($shell_命令)失败?

Bash 究竟为什么result=$($shell_命令)失败?,bash,unix,find,Bash,Unix,Find,为什么分配命令输出在某些情况下有效,而在其他情况下似乎无效?我创建了一个最小的脚本来显示我的意思,我在一个目录中运行它,其中还有一个文件a.txt。请看这个???在下面的脚本,让我知道什么是错误的,也许尝试一下。谢谢 #!/bin/bash ## setup so anyone can copy/paste/run this script ("complete" part of MCVE) tempdir=$(mktemp -d "${TMPDIR:-/tmp}"/demo.XXXX) ||

为什么分配命令输出在某些情况下有效,而在其他情况下似乎无效?我创建了一个最小的脚本来显示我的意思,我在一个目录中运行它,其中还有一个文件a.txt。请看这个???在下面的脚本,让我知道什么是错误的,也许尝试一下。谢谢

#!/bin/bash

## setup so anyone can copy/paste/run this script ("complete" part of MCVE)
tempdir=$(mktemp -d "${TMPDIR:-/tmp}"/demo.XXXX) || exit # make a temporary directory
trap 'rm -rf "$tempdir"' 0 # delete temporary directory on exit
cd "$tempdir" || exit      # don't risk changing non-temporary directories
touch a.txt                # create a sample file

cmd1="find . -name 'a*' -print"
eval $cmd1         # this produces "./a.txt" as expected
res1=$($cmd1)
echo "res1=$res1"  # ??? THIS PRODUCES ONLY "res1=" , $res1 is blank  ???

# let's try this as a comparison

cmd2="ls a*"
res2=$($cmd2)
echo "res2=$res2"  # this produces "res2=a.txt"

让我们来看看这到底是做什么的:

cmd1="find . -name 'a*' -print"
res1=$($cmd1)
echo "res1=$res1"  # ??? THIS PRODUCES ONLY "res1=" , $res1 is blank  ???
根据,执行
res1=$($cmd1)
执行以下操作,假设您没有名称以
'a
开头,以
'
结尾的文件(是的,名称中有单引号),并且您没有启用
nullglob
shell选项:

res1=$( find . -name "'a*'" -print )
注意引用的不是名字吗?引用表示
被视为数据,而不是语法;因此,它们不是对是否扩展
*
有任何影响,而是作为任何文件名的一部分所需的附加元素,以便匹配,这就是为什么您得到的结果根本不匹配。相反,正如常见问题解答所告诉您的,请使用以下函数:

cmd1() {
  find . -name 'a*' -print
}
res1=$(cmd1)
…或数组:

cmd1=( find . -name 'a*' -print )
res1=$( "${cmd1[@]}" )

现在,为什么会发生这种情况?阅读常见问题解答以获得完整的解释。简而言之:参数扩展发生在已经应用了语法引号之后。从安全角度来看,这实际上是一件非常好的事情——如果所有扩展都递归地通过完整解析运行,那么在bash中编写安全代码来处理恶意数据将是不可能的


现在,如果您不关心安全性,也不关心最佳做法,而且您也不关心能够正确解释具有异常文件名的结果:

cmd1="find . -name 'a*' -print"
res1=$(eval "$cmd1") # Force parsing process to restart from beginning. DANGEROUS if cmd1
                     # is not static (ie. constructed with user input or filenames);
                     # prone to being used for shell injection attacks.
echo "res1=$res1"

…但不要那样做。(只有当一个人做不到的时候,他才能摆脱草率的做法,而做不到的时候可能会令人不快;对于我以前的一份工作中的系统管理员人员来说,这一点发生在一个备份维护脚本删除了几TB的计费数据时,因为缓冲区溢出将随机垃圾放在了一个即将删除的文件名中). 阅读常见问题解答,按照其中包含的实践操作。

让我们来看看它到底起到了什么作用:

cmd1="find . -name 'a*' -print"
res1=$($cmd1)
echo "res1=$res1"  # ??? THIS PRODUCES ONLY "res1=" , $res1 is blank  ???
根据,执行
res1=$($cmd1)
执行以下操作,假设您没有名称以
'a
开头,以
'
结尾的文件(是的,名称中有单引号),并且您没有启用
nullglob
shell选项:

res1=$( find . -name "'a*'" -print )
注意引用的不是名字吗?引用表示
被视为数据,而不是语法;因此,它们不是对是否扩展
*
有任何影响,而是作为任何文件名的一部分所需的附加元素,以便匹配,这就是为什么您得到的结果根本不匹配。相反,正如常见问题解答所告诉您的,请使用以下函数:

cmd1() {
  find . -name 'a*' -print
}
res1=$(cmd1)
…或数组:

cmd1=( find . -name 'a*' -print )
res1=$( "${cmd1[@]}" )

现在,为什么会发生这种情况?阅读常见问题解答以获得完整的解释。简而言之:参数扩展发生在已经应用了语法引号之后。从安全角度来看,这实际上是一件非常好的事情——如果所有扩展都递归地通过完整解析运行,那么在bash中编写安全代码来处理恶意数据将是不可能的


现在,如果您不关心安全性,也不关心最佳做法,而且您也不关心能够正确解释具有异常文件名的结果:

cmd1="find . -name 'a*' -print"
res1=$(eval "$cmd1") # Force parsing process to restart from beginning. DANGEROUS if cmd1
                     # is not static (ie. constructed with user input or filenames);
                     # prone to being used for shell injection attacks.
echo "res1=$res1"

…但不要那样做。(只有当一个人做不到的时候,他才能摆脱草率的做法,而做不到的时候可能会令人不快;对于我以前的一份工作中的系统管理员人员来说,这一点发生在一个备份维护脚本删除了几TB的计费数据时,因为缓冲区溢出将随机垃圾放在了一个即将删除的文件名中). 阅读常见问题解答,按照其中包含的实践操作。

让我们来看看它到底起到了什么作用:

cmd1="find . -name 'a*' -print"
res1=$($cmd1)
echo "res1=$res1"  # ??? THIS PRODUCES ONLY "res1=" , $res1 is blank  ???
根据,执行
res1=$($cmd1)
执行以下操作,假设您没有名称以
'a
开头,以
'
结尾的文件(是的,名称中有单引号),并且您没有启用
nullglob
shell选项:

res1=$( find . -name "'a*'" -print )
注意引用的不是名字吗?引用表示
被视为数据,而不是语法;因此,它们不是对是否扩展
*
有任何影响,而是作为任何文件名的一部分所需的附加元素,以便匹配,这就是为什么您得到的结果根本不匹配。相反,正如常见问题解答所告诉您的,请使用以下函数:

cmd1() {
  find . -name 'a*' -print
}
res1=$(cmd1)
…或数组:

cmd1=( find . -name 'a*' -print )
res1=$( "${cmd1[@]}" )

现在,为什么会发生这种情况?阅读常见问题解答以获得完整的解释。简而言之:参数扩展发生在已经应用了语法引号之后。从安全角度来看,这实际上是一件非常好的事情——如果所有扩展都递归地通过完整解析运行,那么在bash中编写安全代码来处理恶意数据将是不可能的


现在,如果您不关心安全性,也不关心最佳做法,而且您也不关心能够正确解释具有异常文件名的结果:

cmd1="find . -name 'a*' -print"
res1=$(eval "$cmd1") # Force parsing process to restart from beginning. DANGEROUS if cmd1
                     # is not static (ie. constructed with user input or filenames);
                     # prone to being used for shell injection attacks.
echo "res1=$res1"

…但不要那样做。(只有当一个人做不到的时候,他才能摆脱草率的做法,而做不到的时候可能会令人不快;对于我以前的一份工作中的系统管理员人员来说,这一点发生在一个备份维护脚本删除了几TB的计费数据时,因为缓冲区溢出将随机垃圾放在了一个即将删除的文件名中). 阅读常见问题解答,按照其中包含的实践操作。

让我们来看看它到底起到了什么作用:

cmd1="find . -name 'a*' -print"
res1=$($cmd1)
echo "res1=$res1"  # ??? THIS PRODUCES ONLY "res1=" , $res1 is blank  ???
根据,执行
res1=$($cmd1)
执行以下操作,假设您没有名称以
'a
开头,以
结尾的文件(是的,名称中有单引号),并且您没有