0

我正在尝试转到当前目录和所有子目录,并在每个以 .sql 结尾的文件中添加一些注释

这是代码片段

HEADER="--SQL HEADER"

for f in 'find . -name *.sql';
do
        echo $f
        echo -e $HEADER > $f.tmp;
        FNAME=${f//\//_/};
        echo -e "\n\n--MORE ANNOTATIONS ${FNAME%.*}:1" >> $f.tmp;
        cat $f >> $f.tmp;
        mv $f.tmp $f;
        rm $f.tmp
done;

我是 bash 的初学者,所以我认为我遇到的一些错误可能是由于带有循环的 find 语句,但这是我得到的错误

find . -name X.sql A.sql W.sql E.sql S.sql
./annotate.sh: line 6: $f.tmp: ambiguous redirect
./annotate.sh: line 8: $f.tmp: ambiguous redirect
./annotate.sh: line 9: $f.tmp: ambiguous redirect
mv: invalid option -- n
Try `mv --help' for more information.
rm: invalid option -- n
Try `rm --help' for more information.

任何帮助将不胜感激=)

4

2 回答 2

3

这就是问题所在。你的“回声”泄露了它:

echo $f

输出

find . -name X.sql A.sql W.sql E.sql S.sql

我认为问题是你在 find 命令中有直单引号(''),而不是反引号(``)。所以它并不是真正运行查找,而是简单地扩展通配符。

您可能必须引用通配符,以便将其传递给 find 而不是由 shell 评估:

for f in `find . -name \*.sql`;

但是,您的脚本中有几个问题,如果您想多次使用它,您应该解决这些问题。请参阅ormaaj 的回答

于 2012-04-19T19:22:40.730 回答
2

正如已经指出的那样,问题在于 find 实际上并没有被执行。然而,这种模式是非常错误的。使用 for 循环对命令替换发生的任何事情进行迭代都不起作用,因为将输出拆分为单词需要进行单词拆分,这不需要引用,即使禁用了路径名扩展也是一个问题,因为文件名可以包含换行符。

最好使用-exec. 首先将此脚本写入文件并chmod u+x scriptname

#!/usr/bin/env bash
header="--SQL HEADER"

for f in "$@"; do
    echo "$f" >&2
    fname=${f//\//_/}

    cat - "$f" <<EOF >"$f.tmp"
    ${header}$'\n\n'
    --MORE ANNOTATIONS ${fname%.*}:1
    EOF

    mv "$f.tmp" "$f"
done

然后find像这样运行:

find . -name '*.sql' -exec scriptname {} +

或者,(假设这是 Bash 的最新版本),使用globstar和否find(如果您愿意,ksh 具有类似的功能)。根据作业,这可能会更慢 - shell 必须预先生成文件列表。

#!/usr/bin/env bash
shopt -s globstar

for f in ./**/*.sql; do
    ...

或者,如果您有 Bash 4 和具有必要 GNU 实用程序的系统,请使用-print0.

find . -name '*.sql' -print0 | while IFS= read -rd '' f; do
    # <body of the above for loop here>
done

请参阅: http: //mywiki.wooledge.org/UsingFind

于 2012-04-19T21:37:56.617 回答