bash 不明确的重定向

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10235146/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 02:05:01  来源:igfitidea点击:

ambiguous redirection

linuxbashredirect

提问by Pita

I'm trying to go the current directory and all sub direcotires, and add some annotations into each file that ends in .sql

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

heres a snippet of the code

继承人的代码片段

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;

im a beginner at bash so i think some of the errors im getting might be due to the find statement with the loop but this is the error i get

我是 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.

any help would be greatly appreciated =)

任何帮助将不胜感激 =)

回答by theglauber

Here's the problem. Your "echo" gives it away:

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

echo $f

outputs

输出

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

I think the problem is you have straight single quotes ('') in the find command, instead of backquotes (``). So it's not really running find, but simply expanding the wildcards.

我认为问题在于您在 find 命令中使用了单引号 (''),而不是反引号 (``)。所以它并不是真正运行 find,而是简单地扩展通配符。

You may have to quote the wildcard so it gets passed to find instead of evaluated by the shell:

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

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

However, there are several problems in your script, which you should address if you want to use it more than once. See ormaaj's answer.

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

回答by ormaaj

The problem, as already pointed out, is that find isn't actually being executed. However, this pattern is very wrong. Iterating using a for loop over anything that happens with a command substitution doesn't work because splitting the output into words requires word-splitting, which requires not quoting, which is a problem even if pathname expansion is disabled because filenames can contain newlines.

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

Preferably, use -exec. First write this script to a file and chmod u+x scriptname:

最好使用-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

Then run findlike this:

然后find像这样运行:

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

Alternatively, (and assuming this is a recent version of Bash), use globstarand no find(ksh has a similar feature if you prefer). This may be slower depending upon the job - the shell must pre-generate the list of files.

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

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

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

Alternatively, if you have Bash 4 and a system with the necessary GNU utilities, use -print0.

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

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

See: http://mywiki.wooledge.org/UsingFind

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