构建文件路径&从变量扩展通配符

时间:2016-08-08 19:37:18

标签: bash

input_dir="~/path/to/dir/"
file_ext=".fastq.gz"
input_path="${input_dir}*${file_ext}"

echo "$input_path"
# returns: ~/path/to/dir/*.fastq.gz

for f in "$input_path" ; do echo "$f" ; done

# returns: ~/path/to/dir/*.fastq.gz

我期待所有扩展名为.fastq.gz的文件列表。

1 个答案:

答案 0 :(得分:4)

不幸的是,你不能存储一个glob模式而不会丢失有关哪些元素是什么以及不打算引用的信息。因此,两个单独的变量需要用于前缀和后缀在glob扩展时间,而glob本身在它们之间不加引号:

input_dir=~/path/to/dir/ # ~ must not be in quotes; use $HOME if you want to quote it
file_ext=".fastq.gz"
for f in "${input_dir}"/*"${file_ext}"; do
  echo "Found $f"
done

注意模式 - "$prefix"/*"$suffix" - 两个扩展都在引号内;这可以防止那些扩展部分本身受到字符串拆分或全局扩展的影响。

如果要存储控制如何在shell变量中标识文件的指令,请考虑存储find参数的数组:

# this is an array variable, with one entry per argument
find_args=( ~/path/to/dir -maxdepth 1 -name '*.fastq.gz' )

while IFS= read -r -d '' filename; do
  printf 'Found %q\n' "$filename"
done < <(find "${find_args[@]}" -print0)

另一种选择是尽早执行扩展,并将其结果存储在数组变量中,在for循环中迭代该变量的内容:

input_dir=~/path/to/dir
file_ext=.fastq.gz
input_files=( "$input_dir"/*"$file_ext" )

for f in "${input_files[@]}"; do
  printf 'Found %q\n' "$f"
done

顺便说一下 - 请注意,如果你的glob表达式没有匹配任何文件,那么默认情况下glob会计算表达式本身。因此,检查您的$f 是否实际存在,处理此情况或启用nullglob shell选项(禁用此行为)可能是明智之举你的剧本。

因此:

 shopt -s nullglob # this prevents a non-matching glob from evaluating to itself

...或...

for f in "$input_dir"/*"$file_ext"; do
  # lack of quotes acceptable here because [[ ]] suppresses string-splitting and globbing
  [[ -e $f || -L $f ]] || { printf '%s\n' "$f not found" >&2; continue; }
  printf 'Found %q\n' "$f"
done