将通配结果分配给 Bash 中的变量

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9229870/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 01:31:52  来源:igfitidea点击:

Assign results of globbing to a variable in Bash

bashglob

提问by Rob Fisher

My colleague, Ryan, came to me with a bug in his Bash script, and I identified the problem with this test:

我的同事 Ryan 带着他的 Bash 脚本中的一个错误来找我,我通过这个测试发现了问题:

$ mkdir ryan
$ mkdir ryan/smells-bad
$ FOO=ryan/smells-*
$ echo $FOO
ryan/smells-bad
$ touch $FOO/rotten_eggs
touch: cannot touch `ryan/smells-*/rotten_eggs': No such file or directory

From this I infer that the globbing happens during the echo command, not when the variable FOO is created.

由此我推断全局连接发生在 echo 命令期间,而不是在创建变量 FOO 时发生。

We have a couple of workarounds, in descending order of ungracefulness:

我们有几个变通方法,按不优雅的降序排列:

touch `echo $FOO`/rotten_eggs

Or:

或者:

pushd
cd $FOO
touch rotten_eggs
popd

But neither is satisfying. Am I missing a trick?

但两者都不令人满意。我错过了一个技巧吗?

回答by jordanm

The problem is that the glob will only expand if the file "rotten_eggs" exists, because it is included in the glob pattern. You should use an array.

问题是只有当文件“rotten_eggs”存在时,glob 才会扩展,因为它包含在 glob 模式中。你应该使用一个数组。

FOO=( ryan/smells-* )
touch "${FOO[@]/%//rotten_eggs}"

The FOO array contains everything matched by the glob. The expansion using % appends /rotten_eggs to each element.

FOO 数组包含与 glob 匹配的所有内容。使用 % 的扩展将 /rotten_eggs 附加到每个元素。

回答by jilles

Consider

考虑

for dir in $FOO; do
    touch "$dir/rotten_eggs"
done

Note that this will touchmultiple files if the glob pattern matches more than one pathname.

请注意,touch如果 glob 模式匹配多个路径名,则会出现多个文件。

回答by Sam Liddicott

The code as intended with the result of the glob assigned to the variable would be like this:

分配给变量的 glob 结果的预期代码如下所示:

$ mkdir ryan
$ mkdir ryan/smells-bad
$ FOO=(ryan/smells-*)
$ echo "${FOO[@]}"
ryan/smells-bad
$ echo "$FOO"
ryan/smells-bad
$ touch "$FOO/rotten_eggs"
$ ls -l "$FOO"
total 0
-rw-r--r-- 1 ryan ryan 0 Mar  1 11:17 rotten_eggs

$FOOis actually an array here, but $FOO also works to get the first element of the array.

$FOO这里实际上是一个数组,但 $FOO 也可以用来获取数组的第一个元素。

but, see how the glob can match more than one file (hence the array is a good idea)

但是,看看 glob 如何匹配多个文件(因此数组是一个好主意)

$ mkdir ryan/clean
$ FOO=(ryan/*)
$ echo "$FOO"
ryan/clean
$ echo "${FOO[@]}"
ryan/clean ryan/smells-bad

In these cases the results of the glob is assigned to the variable as desired, rather than the variable being expanded as a glob at point of use.

在这些情况下,glob 的结果会根据需要分配给变量,而不是在使用时将变量扩展为 glob。

Of course this means that the variable should really always be used in double quotation marks "..."otherwise if the filename itself (the glob expansion) also had a *in it, it would glob again.

当然,这意味着变量应该总是用双引号引起来,"..."否则如果文件名本身(glob 扩展)也有一个*,它会再次 glob。

e.g.

例如

$ touch ryan/'*ea*'
$ FOO=(ryan/*ea*)
$ echo "${FOO[@]}"
ryan/clean ryan/*ea*
$ echo ${FOO[@]}
ryan/clean ryan/clean ryan/*ea*

回答by Mark Reed

I would do it like this:

我会这样做:

for FOO in ryan/smells-*; do
  touch "$FOO"/rotten_eggs
done

This way $FOOcontains the actual directory name, not the glob pattern. If there's more than one match, though, it will only contain the last one after the loop, so the array solution might be better for that case.

这种方式$FOO包含实际的目录名称,而不是 glob 模式。但是,如果有多个匹配项,它将只包含循环后的最后一个匹配项,因此数组解决方案可能更适合这种情况。