bash 有没有一种简单的方法可以为一个 glob 设置 nullglob

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9126060/
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:29:06  来源:igfitidea点击:

Is there an easy way to set nullglob for one glob

bashglobshopt

提问by derobert

In bash, if you do this:

在 bash 中,如果你这样做:

mkdir /tmp/empty
array=(/tmp/empty/*)

you find that arraynow has one element, "/tmp/empty/*", not zero as you'd like. Thankfully, this can be avoided by turning on the nullglob shell option using shopt -s nullglob

你会发现array现在有一个元素"/tmp/empty/*",而不是你想要的零。幸运的是,这可以通过使用打开 nullglob shell 选项来避免shopt -s nullglob

But nullglob is global, and when editing an existing shell script, may break things (e.g., did someone check the exit code of ls foo*to check if there are files named starting with "foo"?). So, ideally, I'd like to turn it on only for a small scope—ideally, one filename expansion. You can turn it off again using shopt -u nullglobBut of course only if it was disabled before:

但是 nullglob 是全局的,并且在编辑现有的 shell 脚本时,可能会破坏一些东西(例如,是否有人检查了 的退出代码ls foo*以检查是否存在以“foo”开头的文件?)。因此,理想情况下,我只想为一个小范围启用它 - 理想情况下,一个文件名扩展。您可以使用shopt -u nullglobBut再次关闭它,当然前提是它之前被禁用:

old_nullglob=$(shopt -p | grep 'nullglob$')
shopt -s nullglob
array=(/tmp/empty/*)
eval "$old_nullglob"
unset -v old_nullglob

makes me think there must be a better way. The obvious "put it in a subshell" doesn't work as of course the variable assignment dies with the subshell. Other than waiting for the Austin groupto import ksh93 syntax, is there?

让我觉得一定有更好的方法。明显的“把它放在子shell中”是行不通的,因为变量赋值当然会随着子shell而消失。除了等待Austin组导入ksh93语法,还有吗?

采纳答案by Michael Kropat

With mapfilein Bash 4, you can load an array from a subshell with something like: mapfile array < <(shopt -s nullglob; for f in ./*; do echo "$f"; done). Full example:

随着mapfile在猛砸4,你可以加载一个子shell数组的东西,如:mapfile array < <(shopt -s nullglob; for f in ./*; do echo "$f"; done)。完整示例:

$ shopt nullglob
nullglob        off
$ find
.
./bar baz
./qux quux
$ mapfile array < <(shopt -s nullglob; for f in ./*; do echo "$f"; done)
$ shopt nullglob
nullglob        off
$ echo ${#array[@]}
2
$ echo ${array[0]}
bar baz
$ echo ${array[1]}
qux quux
$ rm *
$ mapfile array < <(shopt -s nullglob; for f in ./*; do echo "$f"; done)
$ echo ${#array[@]}
0
  • Be sure to glob with ./*instead of a bare *when using echoto print the file name
  • Doesn't work with newline characters in the filename :( as pointed out by derobert
  • 用于打印文件名时,请务必使用 glob./*而不是bare*echo
  • 不适用于文件名中的换行符 :( 正如derobert所指出的


If you need to handle newlines in the filename, you will have to do the much more verbose:

如果您需要处理文件名中的换行符,则必须执行更详细的操作:

array=()
while read -r -d $'
shopt -u nullglob
'; do array+=("$REPLY") done < <(shopt -s nullglob; for f in ./*; do printf "$f
shopt -u | grep -q nullglob && changed=true && shopt -s nullglob
... do whatever you want ...
[ $changed ] && shopt -u nullglob; unset changed
"; done)

But by this point, it may be simpler to follow the advice of one of the other answers.

但此时,遵循其他答案之一的建议可能会更简单。

回答by estani

Unset it when done:

完成后取消设置:

local nullglob=$(shopt -p nullglob) ; shopt -s nullglob

And properly (i.e. storing the previous state):

并且正确(即存储以前的状态):

$nullglob ; unset nullglob

回答by Martin Fick

This is just a tiny bit better than your original suggestion:

这只是比你最初的建议好一点点:

VAR=**/*.mp3(N)

... do whatever you want ...

... 做你想做的 ...

$ ls
file1 file2
$ array=( $(shopt -s nullglob; ls foo*) )
$ ls foo*
ls: foo*: No such file or directory
$ echo ${array[*]}
file1 file2

回答by laughing_man

This is the simplest solution I've found:

这是我找到的最简单的解决方案:

For example, to expand the literal **/*.mp3into a glob for only a particular variable, you can use

例如,要将文字扩展**/*.mp3为仅用于特定变量的 glob,您可以使用

##代码##

Source: https://unix.stackexchange.com/a/204944/56160

来源:https: //unix.stackexchange.com/a/204944/56160

回答by chepner

This may be close to what you want; as is, it requires executing a command to expand the glob.

这可能接近你想要的;照原样,它需要执行一个命令来扩展 glob。

##代码##

Instead of setting arrayin the subshell, we create a subshell using $()whose output is captured by array.

我们不是array在子外壳中设置,而是使用$()其输出由array.