测试 glob 在 Bash 中是否有任何匹配项

发布于 2024-09-03 03:43:06 字数 356 浏览 7 评论 0原文

如果我想检查单个文件是否存在,可以使用 test -e filename[ -e filename ] 进行测试。

假设我有一个 glob,我想知道是否存在名称与 glob 匹配的文件。 glob 可以匹配 0 个文件(在这种情况下我不需要执行任何操作),也可以匹配 1 个或多个文件(在这种情况下我需要执行某些操作)。如何测试 glob 是否有任何匹配项? (我不在乎有多少匹配项,如果我可以使用一个 if 语句并且没有循环来完成此操作,那就最好了(只是因为我发现它最具可读性)。

如果 glob 匹配多个文件,则 test -e glob* 会失败。)

If I want to check for the existence of a single file, I can test for it using test -e filename or [ -e filename ].

Supposing I have a glob and I want to know whether any files exist whose names match the glob. The glob can match 0 files (in which case I need to do nothing), or it can match 1 or more files (in which case I need to do something). How can I test whether a glob has any matches? (I don't care how many matches there are, and it would be best if I could do this with one if statement and no loops (simply because I find that most readable).

(test -e glob* fails if the glob matches more than one file.)

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

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

发布评论

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

评论(22

缱绻入梦 2024-09-10 03:43:06

Bash 特定的解决方案:

compgen -G "<glob-pattern>"

转义模式,否则它将被预先扩展为匹配项。

退出状态为:

  • 1 表示不匹配,
  • 0 表示“一个或多个匹配”

stdout 是与 glob 匹配的文件列表
我认为就简洁性和最小化潜在副作用而言,这是最好的选择。

例子:

if compgen -G "/tmp/someFiles*" > /dev/null; then
    echo "Some files exist."
fi

Bash-specific solution:

compgen -G "<glob-pattern>"

Escape the pattern or it'll get pre-expanded into matches.

Exit status is:

  • 1 for no-match,
  • 0 for 'one or more matches'

stdout is a list of files matching the glob.
I think this is the best option in terms of conciseness and minimizing potential side effects.

Example:

if compgen -G "/tmp/someFiles*" > /dev/null; then
    echo "Some files exist."
fi
一生独一 2024-09-10 03:43:06

nullglob shell 选项确实是一个 bashism。

为了避免繁琐的保存和恢复 nullglob 状态的需要,我只将其设置在扩展 glob 的子 shell 中:

if test -n "$(shopt -s nullglob; echo glob*)"
then
    echo found
else
    echo not found
fi

为了更好的可移植性和更灵活的 globbing,请使用 find:

if test -n "$(find . -maxdepth 1 -name 'glob*' -print -quit)"
then
    echo found
else
    echo not found
fi

显式 -print -quit 操作用于 find,而不是默认的隐式 -print 操作,以便 find 一旦找到第一个匹配的文件就会退出搜索条件。当大量文件匹配时,这应该比 echo glob* 或 ls glob* 运行得快得多,并且还避免了过度填充扩展命令行的可能性(某些 shell 有一个4K 长度限制)。

如果 find 感觉有点大材小用,并且可能匹配的文件数量很少,请使用 stat:

if stat -t glob* >/dev/null 2>&1
then
    echo found
else
    echo not found
fi

The nullglob shell option is indeed a bashism.

To avoid the need for a tedious save and restore of the nullglob state, I'd only set it inside the subshell that expands the glob:

if test -n "$(shopt -s nullglob; echo glob*)"
then
    echo found
else
    echo not found
fi

For better portability and more flexible globbing, use find:

if test -n "$(find . -maxdepth 1 -name 'glob*' -print -quit)"
then
    echo found
else
    echo not found
fi

Explicit -print -quit actions are used for find instead of the default implicit -print action so that find will quit as soon as it finds the first file matching the search criteria. Where lots of files match, this should run much faster than echo glob* or ls glob* and it also avoids the possibility of overstuffing the expanded command line (some shells have a 4K length limit).

If find feels like overkill and the number of files likely to match is small, use stat:

if stat -t glob* >/dev/null 2>&1
then
    echo found
else
    echo not found
fi
仲春光 2024-09-10 03:43:06

我喜欢

exists() {
    [ -e "$1" ]
}

if exists glob*; then
    echo found
else
    echo not found
fi

这既可读又高效(除非有大量文件)。
主要缺点是它比看起来要微妙得多,有时我觉得有必要添加很长的评论。
如果存在匹配项,"glob*" 将由 shell 展开,并将所有匹配项传递给 exists(),后者检查第一个匹配项并忽略其余匹配项。< br>
如果没有匹配,"glob*" 会被传递给 exists(),并且发现那里也不存在。

编辑:可能存在误报,请参阅 评论< /a>

I like

exists() {
    [ -e "$1" ]
}

if exists glob*; then
    echo found
else
    echo not found
fi

This is both readable and efficient (unless there are a huge number of files).
The main drawback is that it's much more subtle than it looks, and I sometimes feel compelled to add a long comment.
If there's a match, "glob*" is expanded by the shell and all the matches are passed to exists(), which checks the first one and ignores the rest.
If there's no match, "glob*" is passed to exists() and found not to exist there either.

Edit: there may be a false positive, see comment

糖果控 2024-09-10 03:43:06
#!/usr/bin/env bash

# If it is set, then an unmatched glob is swept away entirely -- 
# replaced with a set of zero words -- 
# instead of remaining in place as a single word.
shopt -s nullglob

M=(*px)

if [ "${#M[*]}" -ge 1 ]; then
    echo "${#M[*]} matches."
else
    echo "No such files."
fi
#!/usr/bin/env bash

# If it is set, then an unmatched glob is swept away entirely -- 
# replaced with a set of zero words -- 
# instead of remaining in place as a single word.
shopt -s nullglob

M=(*px)

if [ "${#M[*]}" -ge 1 ]; then
    echo "${#M[*]} matches."
else
    echo "No such files."
fi
素食主义者 2024-09-10 03:43:06

如果你设置了 globfail 你可以使用这个疯狂的(你真的不应该)

shopt -s failglob # exit if * does not match 
( : * ) && echo 0 || echo 1

或者

q=( * ) && echo 0 || echo 1

If you have globfail set you can use this crazy (which you really should not)

shopt -s failglob # exit if * does not match 
( : * ) && echo 0 || echo 1

or

q=( * ) && echo 0 || echo 1
昔梦 2024-09-10 03:43:06

test -e 有一个不幸的警告,它认为损坏的符号链接不存在。所以您可能也想检查一下。

function globexists {
  test -e "$1" -o -L "$1"
}

if globexists glob*; then
    echo found
else
    echo not found
fi

test -e has the unfortunate caveat that it considers broken symbolic links to not exist. So you may want to check for those, too.

function globexists {
  test -e "$1" -o -L "$1"
}

if globexists glob*; then
    echo found
else
    echo not found
fi
离去的眼神 2024-09-10 03:43:06

我还有另一个解决方案:

if [ "$(echo glob*)" != 'glob*' ]

这对我来说效果很好。我可能错过了一些极端情况。

I have yet another solution:

if [ "$(echo glob*)" != 'glob*' ]

This works nicely for me. There may be some corner cases I missed.

月下伊人醉 2024-09-10 03:43:06

根据 flabdablet 的答案,对我来说,看起来最简单(不一定是最快)就是使用 find 本身,同时在 shell 上保留 glob 扩展,例如:

find /some/{p,long-p}ath/with/*globs* -quit &> /dev/null && echo "MATCH"

或者在 if 中,例如:

if find $yourGlob -quit &> /dev/null; then
    echo "MATCH"
else
    echo "NOT-FOUND"
fi

Based on flabdablet's answer, for me it looks like easiest (not necessarily fastest) is just to use find itself, while leaving glob expansion on shell, like:

find /some/{p,long-p}ath/with/*globs* -quit &> /dev/null && echo "MATCH"

Or in if like:

if find $yourGlob -quit &> /dev/null; then
    echo "MATCH"
else
    echo "NOT-FOUND"
fi
ぽ尐不点ル 2024-09-10 03:43:06

为了稍微简化 miku 的答案,根据他的想法:

M=(*py)
if [ -e ${M[0]} ]; then
  echo Found
else
  echo Not Found
fi

To simplify miku's answer somewhat, based on his idea:

M=(*py)
if [ -e ${M[0]} ]; then
  echo Found
else
  echo Not Found
fi
哎呦我呸! 2024-09-10 03:43:06

在 Bash 中,您可以通配到数组;如果 glob 不匹配,您的数组将包含一个与现有文件不对应的条目:

#!/bin/bash

shellglob='*.sh'

scripts=($shellglob)

if [ -e "${scripts[0]}" ]
then stat "${scripts[@]}"
fi

注意:如果您设置了 nullglob,则 scripts 将是一个空数组,您应该使用 [ "${scripts[*]}" ][ "${#scripts[*]}" != 0 ] 相反。如果您正在编写一个必须使用或不使用 nullglob 的库,那么您将需要

if [ "${scripts[*]}" ] && [ -e "${scripts[0]}" ]

这种方法的优点是您可以获得要使用的文件列表,而不必重复全局操作。

In Bash, you can glob to an array; if the glob didn't match, your array will contain a single entry that doesn't correspond to an existing file:

#!/bin/bash

shellglob='*.sh'

scripts=($shellglob)

if [ -e "${scripts[0]}" ]
then stat "${scripts[@]}"
fi

Note: if you have nullglob set, scripts will be an empty array, and you should test with [ "${scripts[*]}" ] or with [ "${#scripts[*]}" != 0 ] instead. If you're writing a library that must work with or without nullglob, you'll want

if [ "${scripts[*]}" ] && [ -e "${scripts[0]}" ]

An advantage of this approach is that you then have the list of files you want to work with, rather than having to repeat the glob operation.

摇划花蜜的午后 2024-09-10 03:43:06

如果要在迭代文件之前测试文件是否存在,可以使用此模式:

  for F in glob*; do
    if [[ ! -f $F ]]; then break; fi
    
    ...

  done

如果 glob 不匹配任何内容,则 $F 将是非扩展 glob(在本例中为“glob*”),并且如果不存在同名文件,它将跳过循环的其余部分。

If you want to test if the files exist before iterating over them, you can use this pattern:

  for F in glob*; do
    if [[ ! -f $F ]]; then break; fi
    
    ...

  done

if the glob does not does not match anything, $F will be the non-expanded glob ('glob*' in this case) and if a file with the same name does not exist, it will skip the rest of the loop.

ぺ禁宫浮华殁 2024-09-10 03:43:06
#!/bin/bash
set nullglob
touch /tmp/foo1 /tmp/foo2 /tmp/foo3
FOUND=0
for FILE in /tmp/foo*
do
    FOUND=$((${FOUND} + 1))
done
if [ ${FOUND} -gt 0 ]; then
    echo "I found ${FOUND} matches"
else
    echo "No matches found"
fi
#!/bin/bash
set nullglob
touch /tmp/foo1 /tmp/foo2 /tmp/foo3
FOUND=0
for FILE in /tmp/foo*
do
    FOUND=$((${FOUND} + 1))
done
if [ ${FOUND} -gt 0 ]; then
    echo "I found ${FOUND} matches"
else
    echo "No matches found"
fi
铁轨上的流浪者 2024-09-10 03:43:06
set -- glob*
if [ -f "$1" ]; then
  echo "It matched"
fi

说明

glob* 不匹配时,$1 将包含 'glob*'。测试 -f "$1" 不会为 true,因为 glob* 文件不存在。

为什么这比替代方案更好

这适用于 sh 及其衍生产品:KornShell 和 Bash。它不会创建任何子 shell。 $(..)`...` 命令创建一个子 shell;他们分叉了一个进程,因此比这个解决方案慢。

set -- glob*
if [ -f "$1" ]; then
  echo "It matched"
fi

Explanation

When there isn't a match for glob*, then $1 will contain 'glob*'. The test -f "$1" won't be true because the glob* file doesn't exist.

Why this is better than alternatives

This works with sh and derivates: KornShell and Bash. It doesn't create any sub-shell. $(..) and `...` commands create a sub-shell; they fork a process, and therefore are slower than this solution.

就像 Bash 中的这样(包含 pattern 的测试文件):

shopt -s nullglob
compgen -W *pattern* &>/dev/null
case $? in
    0) echo "only one file match" ;;
    1) echo "more than one file match" ;;
    2) echo "no file match" ;;
esac

它比 compgen 好得多-G:因为我们可以区分更多的情况,更精确。

它只能与一个通配符 * 一起使用。

Like this in Bash (test files containing pattern):

shopt -s nullglob
compgen -W *pattern* &>/dev/null
case $? in
    0) echo "only one file match" ;;
    1) echo "more than one file match" ;;
    2) echo "no file match" ;;
esac

It's far better than compgen -G: because we can discriminates more cases and more precisely.

It can work with only one wildcard *.

任谁 2024-09-10 03:43:06

这个令人厌恶的东西似乎起作用了:

#!/usr/bin/env bash
shopt -s nullglob
if [ "`echo *py`" != "" ]; then
    echo "Glob matched"
else
    echo "Glob did not match"
fi

它可能需要 bash,而不是 sh。

这是有效的,因为如果没有匹配项,nullglob 选项会导致 glob 计算为空字符串。因此,echo 命令的任何非空输出都表明 glob 与某些内容匹配。

This abomination seems to work:

#!/usr/bin/env bash
shopt -s nullglob
if [ "`echo *py`" != "" ]; then
    echo "Glob matched"
else
    echo "Glob did not match"
fi

It probably requires bash, not sh.

This works because the nullglob option causes the glob to evaluate to an empty string if there are no matches. Thus any non-empty output from the echo command indicates that the glob matched something.

仲春光 2024-09-10 03:43:06

Bash 中扩展 glob (extglob) 的一种解决方案:

bash -c 

如果至少有一个匹配,则退出状态为 0;如果没有匹配,则退出状态为非零 (2)。标准输出包含以换行符分隔的匹配文件列表(以及包含引用的空格的文件名)。

或者,稍微不同:

bash -c 

与基于 ls 的解决方案的差异:可能更快(未测量),输出中未引用空格的文件名,当没有引用时退出代码 1匹配(不是 2:耸肩:)。

用法示例:

不匹配:

$ bash -c 

至少有一个匹配:

$ bash -c 

使用的概念:

  • ls' 退出代码行为(为 效率,以及-1用于输出控制)。
  • 不在当前 shell 中启用 extglob(通常不需要)。
  • 使用 $ 前缀来解释 \n,以便扩展 glob 模式与 shopt -s extglob 位于不同的行上code>——否则扩展的 glob 模式将是语法错误!

注 1: 我致力于此解决方案,因为其他答案中建议的 compgen -G "" 方法似乎无法与 大括号扩展;但我需要一些更高级的通配符功能。

注2:扩展 glob 语法的可爱资源:extglob

shopt -s extglob \n /bin/ls -1U <ext-glob-pattern>'

如果至少有一个匹配,则退出状态为 0;如果没有匹配,则退出状态为非零 (2)。标准输出包含以换行符分隔的匹配文件列表(以及包含引用的空格的文件名)。

或者,稍微不同:


与基于 ls 的解决方案的差异:可能更快(未测量),输出中未引用空格的文件名,当没有引用时退出代码 1匹配(不是 2:耸肩:)。

用法示例:

不匹配:


至少有一个匹配:


使用的概念:

  • ls' 退出代码行为(为 效率,以及-1用于输出控制)。
  • 不在当前 shell 中启用 extglob(通常不需要)。
  • 使用 $ 前缀来解释 \n,以便扩展 glob 模式与 shopt -s extglob 位于不同的行上code>——否则扩展的 glob 模式将是语法错误!

注 1: 我致力于此解决方案,因为其他答案中建议的 compgen -G "" 方法似乎无法与 大括号扩展;但我需要一些更高级的通配符功能。

注2:扩展 glob 语法的可爱资源:extglob

shopt -s extglob \n compgen -G <ext-glob-pattern>'

与基于 ls 的解决方案的差异:可能更快(未测量),输出中未引用空格的文件名,当没有引用时退出代码 1匹配(不是 2:耸肩:)。

用法示例:

不匹配:


至少有一个匹配:


使用的概念:

  • ls' 退出代码行为(为 效率,以及-1用于输出控制)。
  • 不在当前 shell 中启用 extglob(通常不需要)。
  • 使用 $ 前缀来解释 \n,以便扩展 glob 模式与 shopt -s extglob 位于不同的行上code>——否则扩展的 glob 模式将是语法错误!

注 1: 我致力于此解决方案,因为其他答案中建议的 compgen -G "" 方法似乎无法与 大括号扩展;但我需要一些更高级的通配符功能。

注2:扩展 glob 语法的可爱资源:extglob

shopt -s extglob \n /bin/ls -1U <ext-glob-pattern>'

如果至少有一个匹配,则退出状态为 0;如果没有匹配,则退出状态为非零 (2)。标准输出包含以换行符分隔的匹配文件列表(以及包含引用的空格的文件名)。

或者,稍微不同:


与基于 ls 的解决方案的差异:可能更快(未测量),输出中未引用空格的文件名,当没有引用时退出代码 1匹配(不是 2:耸肩:)。

用法示例:

不匹配:


至少有一个匹配:


使用的概念:

  • ls' 退出代码行为(为 效率,以及-1用于输出控制)。
  • 不在当前 shell 中启用 extglob(通常不需要)。
  • 使用 $ 前缀来解释 \n,以便扩展 glob 模式与 shopt -s extglob 位于不同的行上code>——否则扩展的 glob 模式将是语法错误!

注 1: 我致力于此解决方案,因为其他答案中建议的 compgen -G "" 方法似乎无法与 大括号扩展;但我需要一些更高级的通配符功能。

注2:扩展 glob 语法的可爱资源:extglob

shopt -s extglob \n /bin/ls -1U @(*.foo|*.bar)'; echo "exit status: $?" /bin/ls: cannot access '@(*.foo|*.bar)': No such file or directory exit status: 2

至少有一个匹配:

使用的概念:

  • ls' 退出代码行为(为 效率,以及-1用于输出控制)。
  • 不在当前 shell 中启用 extglob(通常不需要)。
  • 使用 $ 前缀来解释 \n,以便扩展 glob 模式与 shopt -s extglob 位于不同的行上code>——否则扩展的 glob 模式将是语法错误!

注 1: 我致力于此解决方案,因为其他答案中建议的 compgen -G "" 方法似乎无法与 大括号扩展;但我需要一些更高级的通配符功能。

注2:扩展 glob 语法的可爱资源:extglob

shopt -s extglob \n /bin/ls -1U <ext-glob-pattern>'

如果至少有一个匹配,则退出状态为 0;如果没有匹配,则退出状态为非零 (2)。标准输出包含以换行符分隔的匹配文件列表(以及包含引用的空格的文件名)。

或者,稍微不同:

与基于 ls 的解决方案的差异:可能更快(未测量),输出中未引用空格的文件名,当没有引用时退出代码 1匹配(不是 2:耸肩:)。

用法示例:

不匹配:

至少有一个匹配:

使用的概念:

  • ls' 退出代码行为(为 效率,以及-1用于输出控制)。
  • 不在当前 shell 中启用 extglob(通常不需要)。
  • 使用 $ 前缀来解释 \n,以便扩展 glob 模式与 shopt -s extglob 位于不同的行上code>——否则扩展的 glob 模式将是语法错误!

注 1: 我致力于此解决方案,因为其他答案中建议的 compgen -G "" 方法似乎无法与 大括号扩展;但我需要一些更高级的通配符功能。

注2:扩展 glob 语法的可爱资源:extglob

shopt -s extglob \n compgen -G <ext-glob-pattern>'

与基于 ls 的解决方案的差异:可能更快(未测量),输出中未引用空格的文件名,当没有引用时退出代码 1匹配(不是 2:耸肩:)。

用法示例:

不匹配:

至少有一个匹配:

使用的概念:

  • ls' 退出代码行为(为 效率,以及-1用于输出控制)。
  • 不在当前 shell 中启用 extglob(通常不需要)。
  • 使用 $ 前缀来解释 \n,以便扩展 glob 模式与 shopt -s extglob 位于不同的行上code>——否则扩展的 glob 模式将是语法错误!

注 1: 我致力于此解决方案,因为其他答案中建议的 compgen -G "" 方法似乎无法与 大括号扩展;但我需要一些更高级的通配符功能。

注2:扩展 glob 语法的可爱资源:extglob

shopt -s extglob \n /bin/ls -1U <ext-glob-pattern>'

如果至少有一个匹配,则退出状态为 0;如果没有匹配,则退出状态为非零 (2)。标准输出包含以换行符分隔的匹配文件列表(以及包含引用的空格的文件名)。

或者,稍微不同:

与基于 ls 的解决方案的差异:可能更快(未测量),输出中未引用空格的文件名,当没有引用时退出代码 1匹配(不是 2:耸肩:)。

用法示例:

不匹配:

至少有一个匹配:

使用的概念:

  • ls' 退出代码行为(为 效率,以及-1用于输出控制)。
  • 不在当前 shell 中启用 extglob(通常不需要)。
  • 使用 $ 前缀来解释 \n,以便扩展 glob 模式与 shopt -s extglob 位于不同的行上code>——否则扩展的 glob 模式将是语法错误!

注 1: 我致力于此解决方案,因为其他答案中建议的 compgen -G "" 方法似乎无法与 大括号扩展;但我需要一些更高级的通配符功能。

注2:扩展 glob 语法的可爱资源:extglob

shopt -s extglob \n /bin/ls -1U @(*.ts|*.mp4)'; echo "exit status: $?" 'video1 with spaces.mp4' video2.mp4 video3.mp4 exit status: 0

使用的概念:

  • ls' 退出代码行为(为 效率,以及-1用于输出控制)。
  • 不在当前 shell 中启用 extglob(通常不需要)。
  • 使用 $ 前缀来解释 \n,以便扩展 glob 模式与 shopt -s extglob 位于不同的行上code>——否则扩展的 glob 模式将是语法错误!

注 1: 我致力于此解决方案,因为其他答案中建议的 compgen -G "" 方法似乎无法与 大括号扩展;但我需要一些更高级的通配符功能。

注2:扩展 glob 语法的可爱资源:extglob

shopt -s extglob \n /bin/ls -1U <ext-glob-pattern>'

如果至少有一个匹配,则退出状态为 0;如果没有匹配,则退出状态为非零 (2)。标准输出包含以换行符分隔的匹配文件列表(以及包含引用的空格的文件名)。

或者,稍微不同:

与基于 ls 的解决方案的差异:可能更快(未测量),输出中未引用空格的文件名,当没有引用时退出代码 1匹配(不是 2:耸肩:)。

用法示例:

不匹配:

至少有一个匹配:

使用的概念:

  • ls' 退出代码行为(为 效率,以及-1用于输出控制)。
  • 不在当前 shell 中启用 extglob(通常不需要)。
  • 使用 $ 前缀来解释 \n,以便扩展 glob 模式与 shopt -s extglob 位于不同的行上code>——否则扩展的 glob 模式将是语法错误!

注 1: 我致力于此解决方案,因为其他答案中建议的 compgen -G "" 方法似乎无法与 大括号扩展;但我需要一些更高级的通配符功能。

注2:扩展 glob 语法的可爱资源:extglob

shopt -s extglob \n compgen -G <ext-glob-pattern>'

与基于 ls 的解决方案的差异:可能更快(未测量),输出中未引用空格的文件名,当没有引用时退出代码 1匹配(不是 2:耸肩:)。

用法示例:

不匹配:

至少有一个匹配:

使用的概念:

  • ls' 退出代码行为(为 效率,以及-1用于输出控制)。
  • 不在当前 shell 中启用 extglob(通常不需要)。
  • 使用 $ 前缀来解释 \n,以便扩展 glob 模式与 shopt -s extglob 位于不同的行上code>——否则扩展的 glob 模式将是语法错误!

注 1: 我致力于此解决方案,因为其他答案中建议的 compgen -G "" 方法似乎无法与 大括号扩展;但我需要一些更高级的通配符功能。

注2:扩展 glob 语法的可爱资源:extglob

shopt -s extglob \n /bin/ls -1U <ext-glob-pattern>'

如果至少有一个匹配,则退出状态为 0;如果没有匹配,则退出状态为非零 (2)。标准输出包含以换行符分隔的匹配文件列表(以及包含引用的空格的文件名)。

或者,稍微不同:

与基于 ls 的解决方案的差异:可能更快(未测量),输出中未引用空格的文件名,当没有引用时退出代码 1匹配(不是 2:耸肩:)。

用法示例:

不匹配:

至少有一个匹配:

使用的概念:

  • ls' 退出代码行为(为 效率,以及-1用于输出控制)。
  • 不在当前 shell 中启用 extglob(通常不需要)。
  • 使用 $ 前缀来解释 \n,以便扩展 glob 模式与 shopt -s extglob 位于不同的行上code>——否则扩展的 glob 模式将是语法错误!

注 1: 我致力于此解决方案,因为其他答案中建议的 compgen -G "" 方法似乎无法与 大括号扩展;但我需要一些更高级的通配符功能。

注2:扩展 glob 语法的可爱资源:extglob

shopt -s extglob \n /bin/ls -1U @(*.foo|*.bar)'; echo "exit status: $?" /bin/ls: cannot access '@(*.foo|*.bar)': No such file or directory exit status: 2

至少有一个匹配:

使用的概念:

  • ls' 退出代码行为(为 效率,以及-1用于输出控制)。
  • 不在当前 shell 中启用 extglob(通常不需要)。
  • 使用 $ 前缀来解释 \n,以便扩展 glob 模式与 shopt -s extglob 位于不同的行上code>——否则扩展的 glob 模式将是语法错误!

注 1: 我致力于此解决方案,因为其他答案中建议的 compgen -G "" 方法似乎无法与 大括号扩展;但我需要一些更高级的通配符功能。

注2:扩展 glob 语法的可爱资源:extglob

shopt -s extglob \n /bin/ls -1U <ext-glob-pattern>'

如果至少有一个匹配,则退出状态为 0;如果没有匹配,则退出状态为非零 (2)。标准输出包含以换行符分隔的匹配文件列表(以及包含引用的空格的文件名)。

或者,稍微不同:

与基于 ls 的解决方案的差异:可能更快(未测量),输出中未引用空格的文件名,当没有引用时退出代码 1匹配(不是 2:耸肩:)。

用法示例:

不匹配:

至少有一个匹配:

使用的概念:

  • ls' 退出代码行为(为 效率,以及-1用于输出控制)。
  • 不在当前 shell 中启用 extglob(通常不需要)。
  • 使用 $ 前缀来解释 \n,以便扩展 glob 模式与 shopt -s extglob 位于不同的行上code>——否则扩展的 glob 模式将是语法错误!

注 1: 我致力于此解决方案,因为其他答案中建议的 compgen -G "" 方法似乎无法与 大括号扩展;但我需要一些更高级的通配符功能。

注2:扩展 glob 语法的可爱资源:extglob

shopt -s extglob \n compgen -G <ext-glob-pattern>'

与基于 ls 的解决方案的差异:可能更快(未测量),输出中未引用空格的文件名,当没有引用时退出代码 1匹配(不是 2:耸肩:)。

用法示例:

不匹配:

至少有一个匹配:

使用的概念:

  • ls' 退出代码行为(为 效率,以及-1用于输出控制)。
  • 不在当前 shell 中启用 extglob(通常不需要)。
  • 使用 $ 前缀来解释 \n,以便扩展 glob 模式与 shopt -s extglob 位于不同的行上code>——否则扩展的 glob 模式将是语法错误!

注 1: 我致力于此解决方案,因为其他答案中建议的 compgen -G "" 方法似乎无法与 大括号扩展;但我需要一些更高级的通配符功能。

注2:扩展 glob 语法的可爱资源:extglob

shopt -s extglob \n /bin/ls -1U <ext-glob-pattern>'

如果至少有一个匹配,则退出状态为 0;如果没有匹配,则退出状态为非零 (2)。标准输出包含以换行符分隔的匹配文件列表(以及包含引用的空格的文件名)。

或者,稍微不同:

与基于 ls 的解决方案的差异:可能更快(未测量),输出中未引用空格的文件名,当没有引用时退出代码 1匹配(不是 2:耸肩:)。

用法示例:

不匹配:

至少有一个匹配:

使用的概念:

  • ls' 退出代码行为(为 效率,以及-1用于输出控制)。
  • 不在当前 shell 中启用 extglob(通常不需要)。
  • 使用 $ 前缀来解释 \n,以便扩展 glob 模式与 shopt -s extglob 位于不同的行上code>——否则扩展的 glob 模式将是语法错误!

注 1: 我致力于此解决方案,因为其他答案中建议的 compgen -G "" 方法似乎无法与 大括号扩展;但我需要一些更高级的通配符功能。

注2:扩展 glob 语法的可爱资源:extglob

A solution for extended globs (extglob) in Bash:

bash -c 

Exit status is 0 if there is at least one match, and non-zero (2) when there is no match. Standard output contains a newline-separated list of matching files (and file names containing spaces they are quoted).

Or, slightly different:

bash -c 

Differences to the ls-based solution: probably faster (not measured), file names with spaces not quoted in output, exit code 1 when there is no match (not 2 :shrug:).

Example usage:

No match:

$ bash -c 

At least one match:

$ bash -c 

Concepts used:

  • ls' exit code behavior (adds -U for efficiency, and -1 for output control).
  • Does not enable extglob in current shell (often not desired).
  • Makes use of the $ prefix so that the \n is interpreted, so that the extended glob pattern is on a different line than the shopt -s extglob -- otherwise the extended glob pattern would be a syntax error!

Note 1: I worked towards this solution because the compgen -G "<glob-pattern>" approach suggested in other answers does not seem to work smoothly with brace expansion; and yet I needed some more advanced globbing features.

Note 2: lovely resource for the extended glob syntax: extglob

shopt -s extglob \n /bin/ls -1U <ext-glob-pattern>'

Exit status is 0 if there is at least one match, and non-zero (2) when there is no match. Standard output contains a newline-separated list of matching files (and file names containing spaces they are quoted).

Or, slightly different:


Differences to the ls-based solution: probably faster (not measured), file names with spaces not quoted in output, exit code 1 when there is no match (not 2 :shrug:).

Example usage:

No match:


At least one match:


Concepts used:

  • ls' exit code behavior (adds -U for efficiency, and -1 for output control).
  • Does not enable extglob in current shell (often not desired).
  • Makes use of the $ prefix so that the \n is interpreted, so that the extended glob pattern is on a different line than the shopt -s extglob -- otherwise the extended glob pattern would be a syntax error!

Note 1: I worked towards this solution because the compgen -G "<glob-pattern>" approach suggested in other answers does not seem to work smoothly with brace expansion; and yet I needed some more advanced globbing features.

Note 2: lovely resource for the extended glob syntax: extglob

shopt -s extglob \n compgen -G <ext-glob-pattern>'

Differences to the ls-based solution: probably faster (not measured), file names with spaces not quoted in output, exit code 1 when there is no match (not 2 :shrug:).

Example usage:

No match:


At least one match:


Concepts used:

  • ls' exit code behavior (adds -U for efficiency, and -1 for output control).
  • Does not enable extglob in current shell (often not desired).
  • Makes use of the $ prefix so that the \n is interpreted, so that the extended glob pattern is on a different line than the shopt -s extglob -- otherwise the extended glob pattern would be a syntax error!

Note 1: I worked towards this solution because the compgen -G "<glob-pattern>" approach suggested in other answers does not seem to work smoothly with brace expansion; and yet I needed some more advanced globbing features.

Note 2: lovely resource for the extended glob syntax: extglob

shopt -s extglob \n /bin/ls -1U <ext-glob-pattern>'

Exit status is 0 if there is at least one match, and non-zero (2) when there is no match. Standard output contains a newline-separated list of matching files (and file names containing spaces they are quoted).

Or, slightly different:


Differences to the ls-based solution: probably faster (not measured), file names with spaces not quoted in output, exit code 1 when there is no match (not 2 :shrug:).

Example usage:

No match:


At least one match:


Concepts used:

  • ls' exit code behavior (adds -U for efficiency, and -1 for output control).
  • Does not enable extglob in current shell (often not desired).
  • Makes use of the $ prefix so that the \n is interpreted, so that the extended glob pattern is on a different line than the shopt -s extglob -- otherwise the extended glob pattern would be a syntax error!

Note 1: I worked towards this solution because the compgen -G "<glob-pattern>" approach suggested in other answers does not seem to work smoothly with brace expansion; and yet I needed some more advanced globbing features.

Note 2: lovely resource for the extended glob syntax: extglob

shopt -s extglob \n /bin/ls -1U @(*.foo|*.bar)'; echo "exit status: $?" /bin/ls: cannot access '@(*.foo|*.bar)': No such file or directory exit status: 2

At least one match:

Concepts used:

  • ls' exit code behavior (adds -U for efficiency, and -1 for output control).
  • Does not enable extglob in current shell (often not desired).
  • Makes use of the $ prefix so that the \n is interpreted, so that the extended glob pattern is on a different line than the shopt -s extglob -- otherwise the extended glob pattern would be a syntax error!

Note 1: I worked towards this solution because the compgen -G "<glob-pattern>" approach suggested in other answers does not seem to work smoothly with brace expansion; and yet I needed some more advanced globbing features.

Note 2: lovely resource for the extended glob syntax: extglob

shopt -s extglob \n /bin/ls -1U <ext-glob-pattern>'

Exit status is 0 if there is at least one match, and non-zero (2) when there is no match. Standard output contains a newline-separated list of matching files (and file names containing spaces they are quoted).

Or, slightly different:

Differences to the ls-based solution: probably faster (not measured), file names with spaces not quoted in output, exit code 1 when there is no match (not 2 :shrug:).

Example usage:

No match:

At least one match:

Concepts used:

  • ls' exit code behavior (adds -U for efficiency, and -1 for output control).
  • Does not enable extglob in current shell (often not desired).
  • Makes use of the $ prefix so that the \n is interpreted, so that the extended glob pattern is on a different line than the shopt -s extglob -- otherwise the extended glob pattern would be a syntax error!

Note 1: I worked towards this solution because the compgen -G "<glob-pattern>" approach suggested in other answers does not seem to work smoothly with brace expansion; and yet I needed some more advanced globbing features.

Note 2: lovely resource for the extended glob syntax: extglob

shopt -s extglob \n compgen -G <ext-glob-pattern>'

Differences to the ls-based solution: probably faster (not measured), file names with spaces not quoted in output, exit code 1 when there is no match (not 2 :shrug:).

Example usage:

No match:

At least one match:

Concepts used:

  • ls' exit code behavior (adds -U for efficiency, and -1 for output control).
  • Does not enable extglob in current shell (often not desired).
  • Makes use of the $ prefix so that the \n is interpreted, so that the extended glob pattern is on a different line than the shopt -s extglob -- otherwise the extended glob pattern would be a syntax error!

Note 1: I worked towards this solution because the compgen -G "<glob-pattern>" approach suggested in other answers does not seem to work smoothly with brace expansion; and yet I needed some more advanced globbing features.

Note 2: lovely resource for the extended glob syntax: extglob

shopt -s extglob \n /bin/ls -1U <ext-glob-pattern>'

Exit status is 0 if there is at least one match, and non-zero (2) when there is no match. Standard output contains a newline-separated list of matching files (and file names containing spaces they are quoted).

Or, slightly different:

Differences to the ls-based solution: probably faster (not measured), file names with spaces not quoted in output, exit code 1 when there is no match (not 2 :shrug:).

Example usage:

No match:

At least one match:

Concepts used:

  • ls' exit code behavior (adds -U for efficiency, and -1 for output control).
  • Does not enable extglob in current shell (often not desired).
  • Makes use of the $ prefix so that the \n is interpreted, so that the extended glob pattern is on a different line than the shopt -s extglob -- otherwise the extended glob pattern would be a syntax error!

Note 1: I worked towards this solution because the compgen -G "<glob-pattern>" approach suggested in other answers does not seem to work smoothly with brace expansion; and yet I needed some more advanced globbing features.

Note 2: lovely resource for the extended glob syntax: extglob

shopt -s extglob \n /bin/ls -1U @(*.ts|*.mp4)'; echo "exit status: $?" 'video1 with spaces.mp4' video2.mp4 video3.mp4 exit status: 0

Concepts used:

  • ls' exit code behavior (adds -U for efficiency, and -1 for output control).
  • Does not enable extglob in current shell (often not desired).
  • Makes use of the $ prefix so that the \n is interpreted, so that the extended glob pattern is on a different line than the shopt -s extglob -- otherwise the extended glob pattern would be a syntax error!

Note 1: I worked towards this solution because the compgen -G "<glob-pattern>" approach suggested in other answers does not seem to work smoothly with brace expansion; and yet I needed some more advanced globbing features.

Note 2: lovely resource for the extended glob syntax: extglob

shopt -s extglob \n /bin/ls -1U <ext-glob-pattern>'

Exit status is 0 if there is at least one match, and non-zero (2) when there is no match. Standard output contains a newline-separated list of matching files (and file names containing spaces they are quoted).

Or, slightly different:

Differences to the ls-based solution: probably faster (not measured), file names with spaces not quoted in output, exit code 1 when there is no match (not 2 :shrug:).

Example usage:

No match:

At least one match:

Concepts used:

  • ls' exit code behavior (adds -U for efficiency, and -1 for output control).
  • Does not enable extglob in current shell (often not desired).
  • Makes use of the $ prefix so that the \n is interpreted, so that the extended glob pattern is on a different line than the shopt -s extglob -- otherwise the extended glob pattern would be a syntax error!

Note 1: I worked towards this solution because the compgen -G "<glob-pattern>" approach suggested in other answers does not seem to work smoothly with brace expansion; and yet I needed some more advanced globbing features.

Note 2: lovely resource for the extended glob syntax: extglob

shopt -s extglob \n compgen -G <ext-glob-pattern>'

Differences to the ls-based solution: probably faster (not measured), file names with spaces not quoted in output, exit code 1 when there is no match (not 2 :shrug:).

Example usage:

No match:

At least one match:

Concepts used:

  • ls' exit code behavior (adds -U for efficiency, and -1 for output control).
  • Does not enable extglob in current shell (often not desired).
  • Makes use of the $ prefix so that the \n is interpreted, so that the extended glob pattern is on a different line than the shopt -s extglob -- otherwise the extended glob pattern would be a syntax error!

Note 1: I worked towards this solution because the compgen -G "<glob-pattern>" approach suggested in other answers does not seem to work smoothly with brace expansion; and yet I needed some more advanced globbing features.

Note 2: lovely resource for the extended glob syntax: extglob

shopt -s extglob \n /bin/ls -1U <ext-glob-pattern>'

Exit status is 0 if there is at least one match, and non-zero (2) when there is no match. Standard output contains a newline-separated list of matching files (and file names containing spaces they are quoted).

Or, slightly different:

Differences to the ls-based solution: probably faster (not measured), file names with spaces not quoted in output, exit code 1 when there is no match (not 2 :shrug:).

Example usage:

No match:

At least one match:

Concepts used:

  • ls' exit code behavior (adds -U for efficiency, and -1 for output control).
  • Does not enable extglob in current shell (often not desired).
  • Makes use of the $ prefix so that the \n is interpreted, so that the extended glob pattern is on a different line than the shopt -s extglob -- otherwise the extended glob pattern would be a syntax error!

Note 1: I worked towards this solution because the compgen -G "<glob-pattern>" approach suggested in other answers does not seem to work smoothly with brace expansion; and yet I needed some more advanced globbing features.

Note 2: lovely resource for the extended glob syntax: extglob

shopt -s extglob \n /bin/ls -1U @(*.foo|*.bar)'; echo "exit status: $?" /bin/ls: cannot access '@(*.foo|*.bar)': No such file or directory exit status: 2

At least one match:

Concepts used:

  • ls' exit code behavior (adds -U for efficiency, and -1 for output control).
  • Does not enable extglob in current shell (often not desired).
  • Makes use of the $ prefix so that the \n is interpreted, so that the extended glob pattern is on a different line than the shopt -s extglob -- otherwise the extended glob pattern would be a syntax error!

Note 1: I worked towards this solution because the compgen -G "<glob-pattern>" approach suggested in other answers does not seem to work smoothly with brace expansion; and yet I needed some more advanced globbing features.

Note 2: lovely resource for the extended glob syntax: extglob

shopt -s extglob \n /bin/ls -1U <ext-glob-pattern>'

Exit status is 0 if there is at least one match, and non-zero (2) when there is no match. Standard output contains a newline-separated list of matching files (and file names containing spaces they are quoted).

Or, slightly different:

Differences to the ls-based solution: probably faster (not measured), file names with spaces not quoted in output, exit code 1 when there is no match (not 2 :shrug:).

Example usage:

No match:

At least one match:

Concepts used:

  • ls' exit code behavior (adds -U for efficiency, and -1 for output control).
  • Does not enable extglob in current shell (often not desired).
  • Makes use of the $ prefix so that the \n is interpreted, so that the extended glob pattern is on a different line than the shopt -s extglob -- otherwise the extended glob pattern would be a syntax error!

Note 1: I worked towards this solution because the compgen -G "<glob-pattern>" approach suggested in other answers does not seem to work smoothly with brace expansion; and yet I needed some more advanced globbing features.

Note 2: lovely resource for the extended glob syntax: extglob

shopt -s extglob \n compgen -G <ext-glob-pattern>'

Differences to the ls-based solution: probably faster (not measured), file names with spaces not quoted in output, exit code 1 when there is no match (not 2 :shrug:).

Example usage:

No match:

At least one match:

Concepts used:

  • ls' exit code behavior (adds -U for efficiency, and -1 for output control).
  • Does not enable extglob in current shell (often not desired).
  • Makes use of the $ prefix so that the \n is interpreted, so that the extended glob pattern is on a different line than the shopt -s extglob -- otherwise the extended glob pattern would be a syntax error!

Note 1: I worked towards this solution because the compgen -G "<glob-pattern>" approach suggested in other answers does not seem to work smoothly with brace expansion; and yet I needed some more advanced globbing features.

Note 2: lovely resource for the extended glob syntax: extglob

shopt -s extglob \n /bin/ls -1U <ext-glob-pattern>'

Exit status is 0 if there is at least one match, and non-zero (2) when there is no match. Standard output contains a newline-separated list of matching files (and file names containing spaces they are quoted).

Or, slightly different:

Differences to the ls-based solution: probably faster (not measured), file names with spaces not quoted in output, exit code 1 when there is no match (not 2 :shrug:).

Example usage:

No match:

At least one match:

Concepts used:

  • ls' exit code behavior (adds -U for efficiency, and -1 for output control).
  • Does not enable extglob in current shell (often not desired).
  • Makes use of the $ prefix so that the \n is interpreted, so that the extended glob pattern is on a different line than the shopt -s extglob -- otherwise the extended glob pattern would be a syntax error!

Note 1: I worked towards this solution because the compgen -G "<glob-pattern>" approach suggested in other answers does not seem to work smoothly with brace expansion; and yet I needed some more advanced globbing features.

Note 2: lovely resource for the extended glob syntax: extglob

遮云壑 2024-09-10 03:43:06

nullglobcompgen 仅在某些 bash shell 上有用。

适用于大多数 shell 的(非递归)解决方案是:

set -- ./glob*                  # or /path/dir/glob*
[ -f "$1" ] || shift            # remove the glob if present.
if    [ "$#" -lt 1 ]
then  echo "at least one file found"
fi

Both nullglob and compgen are useful only on some bash shells.

A (non-recursive) solution that works on most shells is:

set -- ./glob*                  # or /path/dir/glob*
[ -f "$1" ] || shift            # remove the glob if present.
if    [ "$#" -lt 1 ]
then  echo "at least one file found"
fi
眼睛会笑 2024-09-10 03:43:06

假设您可能想要对存在的文件执行某些操作:

mapfile -t exists < <(find "$dirName" -type f -iname '*.zip'); [[ ${#exists} -ne 0 ]] && { echo "Zip files found" ; } || { echo "Zip files not found" ; }

如果您需要对文件执行某些操作,则可以循环访问 exists 数组。

Assuming you may want to do something with the files if they exist:

mapfile -t exists < <(find "$dirName" -type f -iname '*.zip'); [[ ${#exists} -ne 0 ]] && { echo "Zip files found" ; } || { echo "Zip files not found" ; }

You can then loop through the exists array if you need to do something with the files.

陌生 2024-09-10 03:43:06

我想提出一个低技术解决方案:

if ls -d glob* 1>/dev/null 2>/dev/null; then
    echo "glob matched"
else
    echo "glob did not match"
fi

这依赖于 ls 的退出代码:如果文件不存在,则它是非零(即指示错误):

让我们假设我们有文件 glob1glob2。然后 ls -d glob* 扩展为 ls -d glob1 glob2,并且 ls 返回零退出代码(即成功)。

假设不存在这样的文件。然后 ls -d glob* 扩展为 ls -d glob*,它不是现有文件,因此 ls 返回一个非 -零退出代码(即失败)。

不幸的是,当您打开 failglobnullglob 时,此功能将停止工作。

I would like to propose a low-tech solution:

if ls -d glob* 1>/dev/null 2>/dev/null; then
    echo "glob matched"
else
    echo "glob did not match"
fi

This relies on the exit code of ls: it is non-zero (i.e., indicates an error) if the file(s) did not exist:

Let's say we have files glob1 and glob2. Then ls -d glob* expands to ls -d glob1 glob2, and ls returns with a zero exit code (i.e., success).

Let's say that no such file exists. Then ls -d glob* expands to ls -d glob*, which is not an existing file, and therefore ls returns with a non-zero exit code (i.e., failure).

Unfortunately, this stops working when you turn on failglob or nullglob.

温柔一刀 2024-09-10 03:43:06

如果您的目标是“获取文件列表,每行一个,我可以将其提供给其他函数/进程”,一个适当的可移植选项是 printf

如果没有匹配项,printf '%s\n' the_glob* 将不打印任何内容,否则在换行符上打印每个项目,适合管道或进程重定向:

首选用法:将项目读入数组,以很好地处理分词和空结果:
readarray -t the_items readarray -t the_items readarray -t the_items readarray -t the_items readarray -t the_items < <(printf '%s\n' the_glob*)
在此示例中,您现在拥有可以处理"${the_items[@]:-safely}"
的匹配项数组
(如果没有匹配的内容,前面的示例将扩展为“safely”
您还可以检查大小:if (( ${#the_items[@]} > 0 )) 或循环元素:for item in "${the_items[@]}"< /code>

您可以做不太安全的事情,例如 items="$(printf ...)",但随后您会遇到分词问题。

如果你真的想将它分配给一个字符串,printf -v(仅限bash / new zsh)可以避免子shell,只是要小心,因为它会在末尾附加一个额外的换行符:

touch /tmp/{file\ one.log,file\ two.log}
filter="/tmp/*.log"
eval "printf -v var_name '%s\n' $filter"
while read -r item; do
    # this will read an extra blank item at the end
    echo "Got file $item"
done <<< "$var_name"

对于带有glob的变量在其中添加一些 eval: eval "printf '%s\n' ${variable_with_globs}"

touch /tmp/{file\ one.log,file\ two.log}
filter="/tmp/*.log"
readarray -t the_items < <(eval "printf '%s\n' $filter")
for item in "${the_items[@]}"; do
    echo "Got file $item"
done

我更喜欢 printf 而不是替代方案,原因如下:

  • ls / stat - 分词、空格分隔
  • find - 需要非 POSIX 选项
    • 如果 find 无法“cd回”当前工作目录,它也会返回非零退出代码:
    • 试试这个(如果您没有 adm 用户,只需从 /etc/passwd 中选择您自己或 root 以外的用户):
      ( cd ~ ; sudo -u adm find / -maxdepth 1 ; echo $? )
    • 用户 adm 无法“返回”我的家,因此发现失败,退出代码为 1
  • shopt - 我不想弄乱 shell 状态
  • test / [ / [[< /code> - 确定存在和过程值的两步过程。如果您不知道如何填充数组并传递它,这可能很有用(nameref 是您传递数组变量的朋友)

printf 是可移植的(没有非 POSIX)所需的选项(与 find 不同)可以显式地与换行符(或您想要的任何内容)分隔,并且如果 glob 不匹配任何内容,则不打印任何内容。使用数组是可选的,但通常是最安全的选择。避免使用 printf -v 来处理全局变量。

If your goal is "get a list of files, one per line, that I can feed to some other function / process", a decently portable option is printf.

printf '%s\n' the_glob* will print nothing if there are no matches, otherwise prints each item on a newline, suitable for pipes or process redirection:

Preferred usage: read items into an array, to handle wordsplitting and empty results nicely:
readarray -t the_items < <(printf '%s\n' the_glob*)
In this example, you now have an array of matched items you can handle "${the_items[@]:-safely}"
(if nothing matched, the previous example would expand to "safely")
You can also check size: if (( ${#the_items[@]} > 0 )) or loop over elements: for item in "${the_items[@]}"

You can do less safe things, like items="$(printf ...)", but then you'll hit word splitting problems.

If you really want to assign it to a string, printf -v (bash / new zsh only) can avoid subshells, just be careful as it will append an extra newline at the end:

touch /tmp/{file\ one.log,file\ two.log}
filter="/tmp/*.log"
eval "printf -v var_name '%s\n' $filter"
while read -r item; do
    # this will read an extra blank item at the end
    echo "Got file $item"
done <<< "$var_name"

For variables with globs in them, add a sprinkle of eval: eval "printf '%s\n' ${variable_with_globs}"

touch /tmp/{file\ one.log,file\ two.log}
filter="/tmp/*.log"
readarray -t the_items < <(eval "printf '%s\n' $filter")
for item in "${the_items[@]}"; do
    echo "Got file $item"
done

I prefer printf over the alternatives for the following reasons:

  • ls / stat - word splitting, space separated
  • find - requires non-POSIX options
    • find also returns non-zero exit code if it cannot "cd back" to the current working directory:
    • Try this out (if you don't have adm user, just pick a user other than your own or root from /etc/passwd):
      ( cd ~ ; sudo -u adm find / -maxdepth 1 ; echo $? )
    • The user adm cannot "return" to my home, so find fails with exit code 1
  • shopt - I don't want to mess with shell state
  • test / [ / [[ - two step process to determine existence and process values. Maybe useful if you don't know how to just fill an array and pass it around (nameref is your friend for passing array variables)

printf is portable (no non-POSIX options needed, unlike find), can explicitly separate with newlines (or whatever you want), and prints nothing if the glob matches nothing. Using arrays is optional, but generally safest option. Avoid printf -v for globs.

无畏 2024-09-10 03:43:06

ls | grep -q "glob.*"

不是最有效的解决方案(如果目录中有大量文件,它可能会很慢),但它很简单,易于阅读,并且还具有正则表达式更强大的优点与普通的 Bash glob 模式相比。

ls | grep -q "glob.*"

Not the most efficient solution (if there's a ton of files in the directory it might be slowish), but it's simple, easy to read and also has the advantage that regexes are more powerful than plain Bash glob patterns.

扛起拖把扫天下 2024-09-10 03:43:06
[ `ls glob* 2>/dev/null | head -n 1` ] && echo true
[ `ls glob* 2>/dev/null | head -n 1` ] && echo true
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文