在 Bash 中执行包含空格的命令

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/836334/
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-17 20:52:02  来源:igfitidea点击:

Executing commands containing space in Bash

bashshell

提问by Epitaph

I have a file named cmdthat contains a list of Unix commands as follows:

我有一个名为的文件cmd,其中包含一个 Unix 命令列表,如下所示:

hostname
pwd
ls  /tmp
cat /etc/hostname
ls -la
ps -ef | grep java
cat cmd

I have another script that executes the commands in cmd as:

我有另一个脚本,它执行 cmd 中的命令,如下所示:

IFS=$'\n'
clear
for cmds in `cat cmd`
do
        if [  $cmds ] ; then
        $cmds;
        echo "****************************";
        fi
done

The problem is that commands in cmd without spaces run fine, but those with spaces are not correctly interpreted by the script. Following is the output:

问题是 cmd 中没有空格的命令运行良好,但是脚本没有正确解释那些有空格的命令。以下是输出:

patrick-laptop
****************************
/home/patrick/bashFiles
****************************
./prog.sh: line 6: ls  /tmp: No such file or directory
****************************
./prog.sh: line 6: cat /etc/hostname: No such file or directory
****************************
./prog.sh: line 6: ls -la: command not found
****************************
./prog.sh: line 6: ps -ef | grep java: command not found
****************************
./prog.sh: line 6: cat cmd: command not found
****************************

What am I missing here?

我在这里错过了什么?

回答by Bryan Oakley

Try changing the one line to eval $cmdsrather than just $cmds

尝试将一行更改为eval $cmds而不仅仅是$cmds

回答by andrewdotn

You can replace your script with the command

你可以用命令替换你的脚本

sh cmd

The shell's job is to read commands and run them! If you want output/progress indicators, run the shell in verbose mode

shell 的工作是读取命令并运行它们!如果需要输出/进度指示器,请在详细模式下运行 shell

sh -v cmd

回答by jabbie

I personally like this approach better - I don't want to munge the IFSif I don't have to do so. You do need to use an eval if you are going to use pipes in your commands. The pipe needs to be processed by the shell not the command. I believe the shell parses out pipes before the expanding strings.

我个人更喜欢这种方法 -如果我不必这样做,我不想修改IFS。如果要在命令中使用管道,则确实需要使用 eval。管道需要由外壳而不是命令处理。我相信 shell 在扩展字符串之前解析出管道。

Note that if your cmd file contains commands that take input there will be an issue. (But you can always create a new fd for the read command to read from.)

请注意,如果您的 cmd 文件包含接受输入的命令,则会出现问题。(但是你总是可以为 read 命令创建一个新的 fd 来读取。)

clear
while read cmds
do
        if [ -n "$cmds" ] ; then
        eval $cmds
        echo "****************************";
        fi
done < cmd

回答by Ben Blank

Edit:Turns out this fails on pipes and redirection. Thanks, Andomar.

编辑:原来这在管道和重定向上失败。谢谢,安多马尔。

You need to change IFSback inside the loop so that bash knows where to split the arguments:

您需要IFS在循环内部改回,以便 bash 知道在哪里拆分参数:

IFS=$'\n'
clear
for cmds in `cat cmd`
do
    if [ $cmds ] ; then
        IFS=$' \t\n' # the default
        $cmds;
        echo "****************************";
        IFS=$'\n'
    fi
done

回答by Andomar

EDIT: The comment by Ben Blank pointed out that my old answer was wrong, thanks.

编辑:Ben Blank 的评论指出我的旧答案是错误的,谢谢。

Looks like you're executing commands as a single string, so bash sees them as the script/executable name.

看起来您将命令作为单个字符串执行,因此 bash 将它们视为脚本/可执行文件名称。

One way to avoid that would be to invoke bash on the command. Change:

避免这种情况的一种方法是在命令上调用 bash。改变:

    if [  $cmds ] ; then
    $cmds;
    echo "****************************";
    fi

to

    if [  $cmds ] ; then
    bash -c $cmds
    echo "****************************";
    fi

回答by user unknown

sed 'aecho "-----------"' cmd > cmd.sh; bash cmd.sh

sed 'aXX' appends XX to every line. This will not work for multiline-commands like:

sed 'aXX' 将 XX 附加到每一行。这不适用于多行命令,例如:

for f in * 
do 
    something $f
fi

but for single-line commands in most cases, it should do.

但是对于大多数情况下的单行命令,它应该可以。