你怎么传递的文件名其他程序正确的bash脚本? [英] How do you pass on filenames to other programs correctly in bash scripts?

查看:115
本文介绍了你怎么传递的文件名其他程序正确的bash脚本?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

什么成语应该的bash脚本一次使用的(没有的Perl,Python和等请)的到另一个程序的命令行构建出的脚本的参数,同时处理文件名的正确

What idiom should one use in Bash scripts (no Perl, Python, and such please) to build up a command line for another program out of the script's arguments while handling filenames correctly?

通过的正确的,我的意思是处理含有空格或奇怪字符的文件名,而不会无意造成其他程序来处理它们作为独立参数(或在案件< >  —后者,毕竟,有效的,如果 不幸文件名字符,如果正确地转义 —做得更糟)

By correctly, I mean handling filenames with spaces or odd characters without inadvertently causing the other program to handle them as separate arguments (or, in the case of < or > — which are, after all, valid if unfortunate filename characters if properly escaped — doing something even worse).

下面是什么,我的意思是一个制造的例子,在形式不的处理文件名正确:让我们假设这个脚本()建立了一个命令一个命令行(,假定为路径)采取所有的的输入参数和移动的东西,看起来像一个标志前面,然后调用

Here's a made-up example of what I mean, in a form that doesn't handle filenames correctly: Let's assume this script (foo) builds up a command line for a command (bar, assumed to be in the path) by taking all of foo's input arguments and moving anything that looks like a flag to the front, and then invoking bar:

#!/bin/bash
# This is clearly wrong

FILES=
FLAGS=
for ARG in "$@"; do
    echo "foo: Handling $ARG"
    if [ x${ARG:0:1} = "x-" ]; then
        # Looks like a flag, add it to the flags string
        FLAGS="$FLAGS $ARG"
    else
        # Looks like a file, add it to the files string
        FILES="$FILES $ARG"
    fi
done

# Call bar with the flags and files (we don't care that they'll
# have an extra space or two)
CMD="bar $FLAGS $FILES"
echo "Issuing: $CMD"
$CMD

(注意,这的只是一个例子的;有很多人需要做这做那一堆args来,然后将它们传递到其他项目其他时间)

(Note that this just an example; there are lots of other times one needs to do this and that to a bunch of args and then pass them onto other programs.)

在一个天真的方案,其中包含简单的文件名,即伟大工程。但是,如果我们假设包含文件的目录

In a naive scenario with simple filenames, that works great. But if we assume a directory containing the files

one
two
three and a half
four < five

那当然命令富* 惨遭失败,其任务:

foo: Handling four < five
foo: Handling one
foo: Handling three and a half
foo: Handling two
Issuing: bar   four < five one three and a half two

如果我们真的让来发出命令,那么,结果将不会是我们期待的东西。

If we actually allow foo to issue that command, well, the results won't be what we're expecting.

previously我试图通过确保有大约每个文件名引号简单的权宜之计来处理这个问题,但我(非常)很快就发现,这是的的正确做法。 : - )

Previously I've tried to handle this through the simple expedient of ensuring that there are quotes around each filename, but I've (very) quickly learned that that is not the correct approach. :-)

那么究竟是什么?约束:

So what is? Constraints:


  1. 我想保持这个成语的尽可能简单(并非最不重要的,所以我能记得的话)。

  2. 我在寻找一个通用的成语,因此,我做了程序及以上的人为的例子,而不是使用一个真实的情景,人们可能很容易(合理)往下走试图在目标程序中使用的功能的路由。

  3. 我要坚持Bash脚本,我不想叫出来Perl,Python和等。

  4. 我很好依赖于(其他)标准的* nix实用工具,如的xargs SED TR 只要我们不要太钝(见上文#1)。 (道歉与Perl,Python等谁认为#3,#4相结合,绘制任意区分程序员。)

  5. 如果它的事项,目标程序也可能是一个Bash脚本,也可能不会。我不希望它重要...

  6. 我不只是想处理的空间,我想处理怪异字符正确也是如此。

  7. 如果它不处理嵌入的NULL字符(字符字面code 0)的文件名,我不打扰。如果有人设法创建一个在他们的文件系统,我不担心它的处理,他们已经尝试的真的很难的把事情搞得一团糟。

  1. I want to keep the idiom as simple as possible (not least so I can remember it).
  2. I'm looking for a general-purpose idiom, hence my making up the bar program and the contrived example above instead of using a real scenario where people might easily (and reasonably) go down the route of trying to use features in the target program.
  3. I want to stick to Bash script, I don't want to call out to Perl, Python, etc.
  4. I'm fine with relying on (other) standard *nix utilities, like xargs, sed, or tr provided we don't get too obtuse (see #1 above). (Apologies to Perl, Python, etc. programmers who think #3 and #4 combine to draw an arbitrary distinction.)
  5. If it matters, the target program might also be a Bash script, or might not. I wouldn't expect it to matter...
  6. I don't just want to handle spaces, I want to handle weird characters correctly as well.
  7. I'm not bothered if it doesn't handle filenames with embedded nul characters (literally character code 0). If someone's managed to create one in their filesystem, I'm not worried about handling it, they've tried really hard to mess things up.

在此先感谢,乡亲们。

修改伊格纳西奥巴斯克斯 - 艾布拉姆斯向我指出猛砸常见问题解答< A HREF =htt​​p://mywiki.wooledge.org/BashFAQ/050相对=nofollow>条目#50 ,该一些阅读和试验后似乎表明,一个方法是使用的击的阵列

Edit: Ignacio Vazquez-Abrams pointed me to Bash FAQ entry #50, which after some reading and experimentation seems to indicate that one way is to use Bash arrays:

#!/bin/bash
# This appears to work, using Bash arrays

# Start with blank arrays
FILES=()
FLAGS=()
for ARG in "$@"; do
    echo "foo: Handling $ARG"
    if [ x${ARG:0:1} = "x-" ]; then
        # Looks like a flag, add it to the flags array
        FLAGS+=("$ARG")
    else
        # Looks like a file, add it to the files array
        FILES+=("$ARG")
    fi
done

# Call bar with the flags and files
echo "Issuing (but properly delimited, not exactly as this appears): bar ${FLAGS[@]} ${FILES[@]}"
bar "${FLAGS[@]}" "${FILES[@]}"

这是否正确,合理?还是我依靠的东西上面的环境以后会咬我。它的看起来的工作,它囊括了所有我的其他框(简单,易记,等等)。它似乎依靠的相对的最近击功能(FAQ条目#50提到V3.1,但我不知道这是否是一般的一些他们正在使用它的语法数组),但我认为这是可能的,我会只处理那些有它的版本。

Is that correct and reasonable? Or am I relying on something environmental above that will bite me later. It seems to work and it ticks all the other boxes for me (simple, easy to remember, etc.). It does appear to rely on a relatively recent Bash feature (FAQ entry #50 mentions v3.1, but I wasn't sure whether that was arrays in general of some of the syntax they were using with it), but I think it's likely I'll only be dealing with versions that have it.

(如果上面是正确的,要取消删除你的答案,伊格纳西奥,我会接受它提供我没有接受任何人的是,虽然我坚持我的发言有关链接只答案。)

推荐答案

?添加文件和标志使用恰当的数组
报价和直接使用引用数组作为参数发出命令。

Why do you want to "build up" a command? Add the files and flags to arrays using proper quoting and issue the command directly using the quoted arrays as arguments.

选择线(省略不变的):

Selected lines from your script (omitting unchanged ones):

if [[ ${ARG:0:1} == - ]]; then    # using a Bash idiom
FLAGS+=("$ARG")                   # add an element to an array
FILES+=("$ARG")
echo "Issuing: bar \"${FLAGS[@]}\" \"${FILES[@]}\""
bar "${FLAGS[@]}" "${FILES[@]}"

有关使用阵列以这种方式快速演示:

For a quick demo of using arrays in this manner:

$ a=(aaa 'bbb ccc' ddd); for arg in "${a[@]}"; do echo "..${arg}.."; done

输出:

..aaa..
..bbb ccc..
..ddd..

请参见 BashFAQ / 050 关于将命令变量。你的脚本不能正常工作的原因是因为没有办法引用引用字符串中的参数。如果你把双引号那里,他们将被视为分隔符字符串本身,而不是一部分。随着参数加引号,分词做和论据,包括空格被视为多个参数。参数以&下;,>或|并非如此,因为他们被视为字符串中的字符重定向和管道变量扩展之前执行在任何情况下的一个问题。

Please see BashFAQ/050 regarding putting commands in variables. The reason that your script doesn't work is because there's no way to quote the arguments within a quoted string. If you were to put quotes there, they would be considered part of the string itself instead of as delimiters. With the arguments left unquoted, word splitting is done and arguments that include spaces are seen as more than one argument. Arguments with "<", ">" or "|" are not a problem in any case since redirection and piping is performed before variable expansion so they are seen as characters in a string.

通过将参数(文件名)在阵列中,空格,换行,等等,都是preserved。通过时,它作为一个参数传递的引用数组变量,它们是pserved的方式来消费计划$ P $。

By putting the arguments (filenames) in an array, spaces, newlines, etc., are preserved. By quoting the array variable when it's passed as an argument, they are preserved on the way to the consuming program.

一些其他注意事项:


  • 使用小写字母(或混合大小写)变量名,以减少他们将与外壳的内置变量碰撞的机会。

  • 如果您在任何现代外壳使用单方括号条件语句,古老的x成语不再是必要的,如果你引用变量(见我的回答的这里)。不过,在Bash中,使用双括号。它们提供的附加功能(见我的回答这里)。

  • 使用 getopts的作为Let_Me_Be建议。您的脚本,虽然我知道这只是一个例子,将无法处理带参数的开关。

  • 为ARG在$ @可缩短至本为ARG (但我preFER更明确的版本可读性)。

  • Use lowercase (or mixed case) variable names to reduce the chance that they will collide with the shell's builtin variables.
  • If you use single square brackets for conditionals in any modern shell, the archaic "x" idiom is no longer necessary if you quote the variables (see my answer here). However, in Bash, use double brackets. They provide additional features (see my answer here).
  • Use getopts as Let_Me_Be suggested. Your script, though I know it's only an example, will not be able to handle switches that take arguments.
  • This for ARG in "$@" can be shortened to this for ARG (but I prefer the readability of the more explicit version).

这篇关于你怎么传递的文件名其他程序正确的bash脚本?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆