将变量中的shell glob扩展为数组

时间:2018-01-30 14:54:05

标签: bash glob

在一个bash脚本中,我有一个包含shell glob表达式的变量,我希望将其扩展为一个匹配文件名数组(nullglob打开),就像在

中一样
pat='dir/*.config'
files=($pat)

即使对于$pat中的多个模式(例如pat="dir/*.config dir/*.conf),这也很有效,但是,我不能在模式中使用转义字符。理想情况下,我希望能够做到

pat='"dir/*" dir/*.config "dir/file with spaces"'

包含文件*,所有文件均以.configfile with spaces结尾。

有一种简单的方法吗? (如果可能,不使用eval。)

当从文件中读取模式时,我不能直接将它放在数组表达式中as proposed in this answer(以及其他各种地方)。

修改

将事情置于上下文中:我要做的是按行读取模板文件并处理#include pattern之类的所有行。然后使用shell glob解析包含。由于此工具是通用的,我希望能够包含带空格和奇怪字符的文件(如*)。

“main”循环如下所示:

    template_include_pat='^#include (.*)$'
    while IFS='' read -r line || [[ -n "$line" ]]; do
        if printf '%s' "$line" | grep -qE "$template_include_pat"; then
            glob=$(printf '%s' "$line" | sed -nrE "s/$template_include_pat/\\1/p")
            cwd=$(pwd -P)
            cd "$targetdir"
            files=($glob)
            for f in "${files[@]}"; do
                printf "\n\n%s\n" "# FILE $f" >> "$tempfile"
                cat "$f" >> "$tempfile" ||
                    die "Cannot read '$f'."
            done
            cd "$cwd"
        else
            echo "$line" >> "$tempfile"
        fi
    done < "$template"

1 个答案:

答案 0 :(得分:2)

使用Python glob模块:

#!/usr/bin/env bash

# Takes literal glob expressions on as argv; emits NUL-delimited match list on output
expand_globs() {
  python -c '
import sys, glob
for arg in sys.argv[1:]:
  for result in glob.iglob(arg):
    sys.stdout.write("%s\0" % (result,))
' _ "$@"
}

template_include_pat='^#include (.*)$'
template=${1:-/dev/stdin}

# record the patterns we were looking for
patterns=( )

while read -r line; do
  if [[ $line =~ $template_include_pat ]]; then
    patterns+=( "${BASH_REMATCH[1]}" )
  fi
done <"$template"

results=( )
while IFS= read -r -d '' name; do
  results+=( "$name" )
done < <(expand_globs "${patterns[@]}")

# Let's display our results:
{
  printf 'Searched for the following patterns, from template %q:\n' "$template"
  (( ${#patterns[@]} )) && printf ' - %q\n' "${patterns[@]}"
  echo
  echo "Found the following files:"
  (( ${#results[@]} )) && printf ' - %q\n' "${results[@]}"
} >&2