Linux 如何正确处理bashshell脚本中的通配符扩展?

Linux 如何正确处理bashshell脚本中的通配符扩展?,linux,bash,unix,shell,Linux,Bash,Unix,Shell,上面是我提供的源(SRC)和设计(DEST)路径的shell脚本。当我没有将通配符“”放入SRC路径时,它工作得很好。当我运行此shell脚本并给出“”pdf或“*”时,如下所示: #!/bin/bash hello() { SRC=$1 DEST=$2 for IP in `cat /opt/ankit/configs/machine.configs` ; do echo $SRC | grep '*' > /dev/null

上面是我提供的源(SRC)和设计(DEST)路径的shell脚本。当我没有将通配符“”放入SRC路径时,它工作得很好。当我运行此shell脚本并给出“”pdf或“*”时,如下所示:

#!/bin/bash

hello()
{
    SRC=$1
    DEST=$2

    for IP in `cat /opt/ankit/configs/machine.configs` ; do
        echo $SRC | grep '*' > /dev/null
        if test `echo $?` -eq 0 ; then
            for STAR in $SRC ; do
                echo -en "$IP"
                echo -en "\n\t ARG1=$STAR ARG2=$2\n\n"
            done
        else
            echo -en "$IP"
            echo -en "\n\t ARG1=$SRC ARG2=$DEST\n\n"
        fi
    done
}

hello $1 $2
#!/bin/bash

hello() {

  SRC=$1
  DEST=$2

   while read IP ; do
     for FILE in $SRC; do
       echo -e "$IP"
       echo -e "\tARG1=$FILE ARG2=$DEST\n"
      done
   done < /tmp/machine.configs
 }

 hello "$1" $2
我得到以下输出:

root@ankit1:~/as_prac# ./test.sh /home/dev/Examples/*.pdf /ankit_test/as
DEST是/ankit_test/as,但由于“*”的原因,DEST也会被人工填充。预期的答案是

192.168.1.6
ARG1=/home/dev/Examples/case_Contact.pdf ARG2=/home/dev/Examples/case_howard_county_library.pdf
所以,如果你明白我想做什么,请帮助我解决这个错误。 我会感谢你的

提前感谢


我需要确切地知道如何在不干扰DEST的情况下在程序中逐个使用“*.pdf”。

除非您转义通配符,否则shell将展开通配符,例如,如果您

ARG1=/home/dev/Examples/case_Contact.pdf ARG2=/ankit_test/as
并按以下方式运行脚本:

$ ls
one.pdf two.pdf three.pdf
这将是一样的

./test.sh *.pdf /ankit__test/as
这不是你所期望的。做

./test.sh one.pdf two.pdf three.pdf /ankit__test/as

应该可以工作。

您还缺少关闭外部for循环的最终“完成”。

无需生成shell来查看
$?
变量,您可以直接计算它

应该是:

./test.sh \*.pdf /ankit__test/as

你的脚本需要更多的工作。 即使在跳过通配符后,您也不会得到预期的答案。您将获得:

if [ $? -eq 0 ]; then
请尝试以下操作:

ARG1=/home/dev/Examples/*.pdf ARG2=/ankit__test/as
按如下方式运行:

for IP in `cat /opt/ankit/configs/machine.configs`
do
    for i in $SRC
    do
        echo -en "$IP"
        echo -en "\n\t ARG1=$i ARG2=$DEST\n\n"
    done
done

好的,这似乎是您想要的:

root@ankit1:~/as_prac# ./test.sh "/home/dev/Examples/*.pdf" /ankit__test/as
./test.sh /ankit_test/as /home/dev/Examples/*.pdf
#/bin/bash
你好(){
SRC=$1
目的地=2美元
读IP时,请执行以下操作:
对于$SRC;do中的文件
echo-e“$IP”
echo-e“\tARG1=$FILE ARG2=$DEST\n”
完成
完成
  • 在调用脚本时,仍然需要转义任何通配符
  • 调用
    hello
    函数时,必须使用双引号,否则仅计算
    $1
    就会导致通配符展开,但我们不希望在函数中分配
    $SRC
    之前发生这种情况

  • 如果可以,请更改传递到shell脚本的参数的顺序,如下所示:

    #!/bin/bash
    
    hello()
    {
        SRC=$1
        DEST=$2
    
        for IP in `cat /opt/ankit/configs/machine.configs` ; do
            echo $SRC | grep '*' > /dev/null
            if test `echo $?` -eq 0 ; then
                for STAR in $SRC ; do
                    echo -en "$IP"
                    echo -en "\n\t ARG1=$STAR ARG2=$2\n\n"
                done
            else
                echo -en "$IP"
                echo -en "\n\t ARG1=$SRC ARG2=$DEST\n\n"
            fi
        done
    }
    
    hello $1 $2
    
    #!/bin/bash
    
    hello() {
    
      SRC=$1
      DEST=$2
    
       while read IP ; do
         for FILE in $SRC; do
           echo -e "$IP"
           echo -e "\tARG1=$FILE ARG2=$DEST\n"
          done
       done < /tmp/machine.configs
     }
    
     hello "$1" $2
    
    这将使你的生活更容易,因为可变部分移动到线的末端。然后,以下脚本将执行您想要的操作:

    root@ankit1:~/as_prac# ./test.sh "/home/dev/Examples/*.pdf" /ankit__test/as
    
    ./test.sh /ankit_test/as /home/dev/Examples/*.pdf
    

    以下是我的想法:

    #!/bin/bash
    hello()
    {
        SRC=$1
        DEST=$2
    
        for IP in `cat /opt/ankit/configs/machine.configs` ; do
            echo -en "$IP"
            echo -en "\n\t ARG1=$SRC ARG2=$DEST\n\n"
        done
    }
    
    arg2=$1
    shift
    while [[ "$1" != "" ]] ; do
            hello $1 $arg2
            shift
    done
    
    我们将传入脚本获得的所有参数,而不是只向hello()函数传递两个参数

    在hello()函数中,我们首先将最后一个参数分配给DEST变量,然后循环所有参数,将每个参数分配给SRC,并使用SRC和DEST参数运行我们想要的任何命令。请注意,如果$SRC和$DEST包含空格,您可能希望在它们周围加上引号。当SRC与DEST相同时,我们停止循环,因为这意味着我们已经到达了最终参数(目标)。

    您正在运行

    #!/bin/bash
    
    hello()
    {
        # DEST will contain the last argument
        eval DEST=\$$#
    
        while [ $1 != $DEST ]; do
            SRC=$1
    
            for IP in `cat /opt/ankit/configs/machine.configs`; do
                echo -en "$IP"
                echo -en "\n\t ARG1=$SRC ARG2=$DEST\n\n"
            done
    
            shift || break
        done
    }
    
    hello $*
    
    在脚本获取通配符之前,您的交互式shell正在扩展通配符。启动时只需引用第一个参数,如中所示

    ./test.sh /home/dev/Examples/*.pdf /ankit_test/as 
    

    然后,在您的脚本中,在您希望使用通配符的任何地方引用“$SRC”(即,当您使用
    echo$SRC
    ,而不是使用
    echo“$SRC”
    ),并在您希望扩展通配符时将其保留为不带引号。基本上,除非您希望解释元字符,否则始终在可能包含shell元字符的内容周围加引号。:)

    对于使用通配符(如*.txt)的多个输入文件,我发现这非常有效,不需要转义。它应该像“ls”或“rm”这样的本地bash应用程序一样工作。这几乎在任何地方都没有记录,因此,由于我花了3天的大部分时间试图弄清楚它,我决定将其发布给未来的读者

    目录包含以下文件(ls的输出)

    像脚本一样运行

    file1.txt file2.txt file3.txt
    
    甚至像

    $ ./script.sh *.txt
    
    剧本

    $ ./script.sh file{1..3}.txt
    
    关键是暂时切换IFS(内部字段分隔符)。您必须确保在切换之前存储该文件,然后在完成上述操作后将其切换回


    现在,您在file[]数组中有了一个扩展文件列表(,其中转义了空格)),您可以在其中循环。我喜欢这个解决方案,因为它是最好的、最容易编程的,对用户来说也是最容易的。

    你说得对,但我想逐一使用所有的“one.pdf、two.pdf、three.pdf”。例如,我需要将这一切复制到另一个位置。那么wat就是解决方案。请帮助我。我在shell脚本方面没有太多经验。所以,我不知道这是一种奇怪的使用方式。我也试过你的,但有以下错误。当使用此./test.sh:line 14:[:missing`]'p.s.时出现此错误。此版本仅使用shell内置程序,因此不需要生成任何子进程来完成其工作。