5

我写了一个 bash 脚本,稍后需要做一些事情。它被称为这样的东西:

later mv *.log /somewhere/else

但是,当这样*.log调用时,在调用时会扩展,并且调用脚本就像我写的一样

later mv 1.log 2.log 3.log /somewhere/else

我试图让我的脚本稍后扩展通配符。我试着这样称呼它

later mv '*.log' /somewhere/else

还有\*, 但这些都导致通配符根本没有得到扩展。

如何在命令行中扩展通配符?有没有办法在调用脚本时防止扩展,即在输入时获取原始参数?

这是我的脚本的一部分,用于为以后的调用做准备:

tmpfile=$(mktemp)

### Get a quoted commandline
line=
while (( "$#" > 0 )); do
        line="$line\"$1\" "
        shift
done

### Prepare a script to be run
echo '#!/bin/bash' > "$tmpfile"
echo "cd $(pwd)" >> "$tmpfile"
echo "trap 'rm \"$tmpfile\"' EXIT" >> "$tmpfile"
echo "$line" >> "$tmpfile"
chmod 777 "$tmpfile"

请注意,我必须引用命令行,因为我的一些文件和文件夹的名称中有空格;如果我删除引用位,即使没有通配符的位也会停止工作。

4

3 回答 3

5

有趣的问题。我怀疑可能有比我更好的答案。尽管如此,鉴于

A='foo.*'

这似乎做你想做的事:

echo $(eval echo "$A")
于 2012-08-03T00:34:38.903 回答
1

最简单的方法可能是简单地将通配符(glob)传回shell进行扩展,

例如:

 #!/bin/bash
 echo "For the wildcard $1"
 echo "I find these match(es): $(eval echo "$1")"

$( … )操作员调用一个子shell,并对结果进行插值;该echo命令只是返回它们。

  • 正如@thb 在他们的回答中所说的那样,eval在 shell 脚本中是必需的(但在交互式 shell 上键入它时不需要,在这种情况下$(echo $1)有效。

请注意,您仍然必须转义间距等,但似乎您已经考虑到了这一点。自然,调用脚本时需要引用 glob ——这就是为什么大多数 Unix 命令只在第一个或最后一个位置使用一个列表的原因,尽管find确实存在这样的例子,它们本身需要转义的 fileglob。

PS:至于强制外壳执行扩展的程序:不,没有内置的方法可以这样做。shell 会在之前(好吧,如果不一定按时间顺序的话,逻辑上是“之前”)扩展 glob,甚至可以识别您的程序所在的文件,并且普遍不知道它运行的程序。

于 2012-08-03T00:29:50.937 回答
0

解决方案

在 shell 脚本中有一堆棘手的字符。空格和两个引号是最难处理的。这个建议的解决方案将通过应用适当的引用来解决棘手字符的问题。

后来的脚本:

#!/bin/bash

if [ $# -lt 1 ]; then
        echo "Need argument!"
        exit 1
fi

### Get a quoted commandline
line=
files=($(echo "$1"))
for file in "${files[@]}"; do
        echo "Debug: Processing file [$file]"
        quoted_filename=$(printf '%q' "$file")
        if [ -n "$line" ]; then
                line="$line "
        fi
        line="$line$quoted_filename"
done
echo -e "Result:\n$line"

测试解决方案

准备:

使用具有潜在缺陷的四个匹配条目准备测试环境:

mkdir 'foo.bar.*'
date > 'foo.bar test.dat'
touch 'foo."nickname".bar'
touch "foo.'single'.bar"

跑:

使用问题中建议的通配符。

./later.sh 'foo*'

示例输出:

Debug: Processing file [foo.bar.*]
Debug: Processing file [foo.bar test.dat]
Debug: Processing file [foo."nickname".bar]
Debug: Processing file [foo.'single'.bar]
Result:
foo.bar.\* foo.bar\ test.dat foo.\"nickname\".bar foo.\'single\'.bar
于 2021-11-04T14:01:18.793 回答