Bash globbing 和参数传递

hig*_*guy 8 bash wildcards arguments glob

我有以下简化的 bash 脚本

#!/bin/bash

files=("$@")

if [ "X$files" = "X" ]; then
  files=$HOME/print/*.pdf;
fi

for file in "${files[@]}"; do
  ls "$file";
done
Run Code Online (Sandbox Code Playgroud)

如果我将参数(文件名)作为参数传递,该脚本将打印正确的文件名。另一方面,如果我不传递参数,它会打印

/home/user/print/*.pdf: No such file or directory
Run Code Online (Sandbox Code Playgroud)

为什么在这种情况下文件名没有扩展,我该如何解决?请注意,我使用files=("$@")and"${files[@]}"结构是因为我读到它比通常的“files=$*”更受欢迎。

Sté*_*las 10

您将分配files标量变量而不是数组变量。

 files=$HOME/print/*.pdf
Run Code Online (Sandbox Code Playgroud)

你分配一些字符串一样/home/highsciguy/print/*.pdf$files标量(又名字符串)变量。

用:

files=(~/print/*.pdf)
Run Code Online (Sandbox Code Playgroud)

或者

files=("$HOME"/print/*.pdf)
Run Code Online (Sandbox Code Playgroud)

反而。shell 会将该通配模式扩展为文件路径列表,并将它们中的每一个分配给$files 数组的元素。

glob 的扩展在赋值时完成。

您不必使用非标准的 sh 功能,您可以通过编写它来使用您的系统sh而不是bash这里:

#!/bin/sh -

[ "$#" -gt 0 ] || set -- ~/print/*.pdf

for file do
  ls -d -- "$file"
done
Run Code Online (Sandbox Code Playgroud)

set是分配"$@"位置参数数组。

另一种方法可能是将通配模式存储在标量变量中:

files=$HOME/print/*.pdf
Run Code Online (Sandbox Code Playgroud)

并让 shell 在$files 变量扩展时扩展 glob 。

IFS= # disable word splitting
for file in $files; do ...
Run Code Online (Sandbox Code Playgroud)

在这里,因为$files没有被引用(你通常不应该这样做),它的扩展会受到分词(我们在这里已经禁用)和通配符/文件名生成的影响。

因此*.pdf 将扩展为匹配文件的列表。但是,如果$HOME包含通配符,它​​们也可以被扩展,这就是为什么仍然最好使用数组变量的原因。