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

发布于 2025-01-02 11:29:44 字数 755 浏览 1 评论 0原文

在 bash 中,如果你这样做:

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

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

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

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

让我觉得一定有更好的方法。明显的“将其放入子 shell 中”不起作用,因为变量赋值当然会随子 shell 一起消失。除了等待Austin组导入ksh93语法之外,还有吗?

In bash, if you do this:

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

you find that array now 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

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 nullglob But of course only if it was disabled before:

old_nullglob=$(shopt -p | grep '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 group to import ksh93 syntax, is there?

) 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 group to import ksh93 syntax, is there?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

ぶ宁プ宁ぶ 2025-01-09 11:29:44

完成后取消设置:

shopt -u nullglob

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

shopt -u | grep -q nullglob && changed=true && shopt -s nullglob
... do whatever you want ...
[ $changed ] && shopt -u nullglob; unset changed

Unset it when done:

shopt -u nullglob

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

shopt -u | grep -q nullglob && changed=true && shopt -s nullglob
... do whatever you want ...
[ $changed ] && shopt -u nullglob; unset changed
美羊羊 2025-01-09 11:29:44

使用 Bash 4 中的 mapfile,您可以从子 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
  • 使用 echo 打印文件名时,请务必使用 ./* 进行 glob,而不是裸露的 *
  • 不适用文件名中的换行符 :( 正如 derobert 所指出的,

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

array=()
while read -r -d 

但到目前为止,遵循这一点可能会更简单其他答案之一的建议。

\0'; do array+=("$REPLY") done < <(shopt -s nullglob; for f in ./*; do printf "$f\0"; done)

但到目前为止,遵循这一点可能会更简单其他答案之一的建议。

With mapfile in 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:

$ 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 echo to print the file name
  • Doesn't work with newline characters in the filename :( as pointed out by derobert

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

array=()
while read -r -d 

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

\0'; do array+=("$REPLY") done < <(shopt -s nullglob; for f in ./*; do printf "$f\0"; done)

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

七堇年 2025-01-09 11:29:44

这比你原来的建议好一点:

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

......做你想做的事......

$nullglob ; unset nullglob

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

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

... do whatever you want ...

$nullglob ; unset nullglob
凤舞天涯 2025-01-09 11:29:44

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

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

我们没有在子 shell 中设置 array,而是使用 $() 创建一个子 shell,其输出由 array 捕获。

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

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

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

再见回来 2025-01-09 11:29:44

这是我发现的最简单的解决方案:

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

VAR=**/*.mp3(N)

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

This is the simplest solution I've found:

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

VAR=**/*.mp3(N)

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文