简体   繁体   English

将命令作为参数传递给bash脚本

[英]pass a command as an argument to bash script

How do I pass a command as an argument to a bash script? 如何将命令作为参数传递给bash脚本? In the following script, I attempted to do that, but it's not working! 在下面的脚本中,我试图这样做,但它不起作用!

#! /bin/sh

if [ $# -ne 2 ]
then
    echo "Usage: $0 <dir> <command to execute>"
    exit 1;
fi;

while read line
do
    $($2) $line
done < $(ls $1);

echo "All Done"

A sample usage of this script would be 此脚本的示例用法是

./myscript thisDir echo

Executing the call above ought to echo the name of all files in the thisDir directory. 执行上面的调用应该回显thisDir目录中所有文件的名称。

your command "echo" command is "hidden" inside a sub-shell from its argments in $line. 你的命令“echo”命令从$ line中的argments中隐藏在子shell中。

I think I understand what your attempting in with $($2) , but its probably overkill, unless this isn't the whole story, so 我想我明白你用$($2)尝试了什么,但它可能有点矫枉过正,除非这不是全部故事,所以

 while read line ; do
    $2 $line
 done < $(ls $1)

should work for your example with thisDir echo . 应该使用thisDir echo来为你的例子工作。 If you really need the cmd-substitution and the subshell, then put you arguments so they can see each other: 如果你真的需要cmd-substitution和subshel​​l,那么就把你的参数放在一起,这样他们就能看到对方:

   $($2 $line)

And as DS mentions, you might need eval before either of these. 正如DS提到的那样,在这些之前你可能需要eval

IHTH IHTH

you could try: (in your codes) 你可以尝试:(在你的代码中)

echo "$2 $line"|sh

or the eval : 或者eval

eval "$2 $line"

First big problem: $($2) $line executes $2 by itself as a command, then tries to run its output (if any) as another command with $line as an argument to it. 第一个大问题: $($2) $line本身作为命令执行$2 ,然后尝试将其输出(如果有的话)作为另一个命令运行,其中$line作为参数。 You just want $2 $line . 你只想要$2 $line

Second big problem: while read ... done < $(ls $1) doesn't read from the list of filenames, it tries to the contents of a file specified by the output of ls -- this will fail in any number of ways depending on the exact circumstances. 第二大问题: while read ... done < $(ls $1)不从文件名列表中读取时,它会尝试ls输出指定的文件内容 - 这将以多种方式失败视具体情况而定。 Process substitution ( while read ... done < <(ls $1) ) would do more-or-less what you want, but it's a bash-only feature (ie you must start the script with #!/bin/bash , not #!/bin/sh ). 进程替换( while read ... done < <(ls $1) )会或多或少地做你想要的,但它只是一个bash-only功能(即你必须#!/bin/bash启动脚本,而不是#!/bin/sh )。 And anyway it's a bad idea to parse ls , you should almost always just use a shell glob ( * ) instead. 无论如何, 解析ls是一个坏主意,你应该几乎总是只使用shell glob( * )。

The script also has some other potential issues with spaces in filenames (using $line without double-quotes around it, etc), and weird stylistic oddities (you don't need ; at the end of a line in shell). 该脚本还有一些其他潜在的问题与文件名中的空格(使用$line ,周围没有双引号等),以及奇怪的风格怪异(你不需要;在shell的一行末尾)。 Here's my stab at a rewrite: 这是我重写的重点:

#! /bin/sh

if [ $# -ne 2 ]; then
    echo "Usage: $0 <dir> <command to execute>"
    exit 1
fi

for file in "$1"/*; do
    $2 "$file"
done

echo "All done"

Note that I didn't put double-quotes around $2 . 请注意,我没有在$2附近$2双引号。 This allows you to specify multiword commands (eg ./myscript thisDir "cat -v" would be interpreted as running the cat command with the -v option, rather than trying to run a command named "cat -v" ). 这允许您指定多字命令(例如./myscript thisDir "cat -v"将被解释为使用-v选项运行cat命令,而不是尝试运行名为"cat -v"的命令)。 It would actually be a bit more flexible to take all arguments after the first one as the command and its argument, allowing you to do eg ./myscript thisDir cat -v , ./myscript thisDir grep -m1 "pattern with spaces" , etc: 在第一个参数之后将所有参数作为命令及其参数实际上会更灵活一点,允许你做例如./myscript thisDir cat -v ,。/ ./myscript thisDir grep -m1 "pattern with spaces"等等:

#! /bin/sh

if [ $# -lt 2 ]; then
    echo "Usage: $0 <dir> <command to execute> [command options]"
    exit 1
fi

dir="$1"
shift

for file in "$dir"/*; do
    "$@" "$file"
done

echo "All done"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM