如何在bash shell脚本中正确处理通配符扩展?

时间:2008-11-03 09:31:29

标签: linux bash unix 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

以上是我提供的shell脚本(SRC)& desitnation(DEST)路径。当我没有使用通配符''放入SRC路径时,它工作正常。当我运行这个shell脚本并给出''。pdf或'*'时,如下所示:

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

我得到以下输出:

192.168.1.6
ARG1=/home/dev/Examples/case_Contact.pdf ARG2=/home/dev/Examples/case_howard_county_library.pdf

DEST是/ ankit_test / as,但由于'*',DEST也会被删除。预期的答案是

ARG1=/home/dev/Examples/case_Contact.pdf ARG2=/ankit_test/as

所以,如果您了解我要做的事情,请帮助我解决这个问题。 我会感激你的。

提前致谢!!!

我需要确切地知道我如何在我的程序中逐一使用'* .pdf'而不会打扰DEST。

9 个答案:

答案 0 :(得分:4)

您的脚本需要更多工作。 即使在逃避通配符后,您也无法获得预期的答案。你会得到:

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

答案 1 :(得分:3)

shell会扩展通配符,除非你将它们转义,例如,如果你有

$ ls
one.pdf two.pdf three.pdf

并以

运行您的脚本
./test.sh *.pdf /ankit__test/as

它与

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

这不是你所期望的。做

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

应该有用。

答案 2 :(得分:2)

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

./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

答案 3 :(得分:1)

您也错过了关闭外部for循环的最终“完成”。

答案 4 :(得分:1)

好的,这似乎可以做你想要的:

#!/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
  1. 调用脚本时仍需要转义任何通配符
  2. 当您调用hello函数时,双引号是必需的,否则仅仅评估$1的事实会导致扩展通配符,但我们不希望在{{1在函数
  3. 中分配

答案 5 :(得分:1)

以下是我提出的建议:

#!/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 $*

我们将传入脚本获得的所有参数,而不是仅将两个参数传递给hello()函数。

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

答案 6 :(得分:1)

对于使用通配符(如* .txt)的多个输入文件,我发现这可以完美地工作,不需要转义。它应该像本地bash应用程序一样工作,如&#34; ls&#34;或&#34; rm。&#34;几乎没有记录在任何地方,因为我花了3天的时间来试图找出它,我决定将它发布给未来的读者。

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

file1.txt file2.txt file3.txt

运行类似

的脚本
$ ./script.sh *.txt

甚至喜欢

$ ./script.sh file{1..3}.txt

脚本

#!/bin/bash

# store default IFS, we need to temporarily change this
sfi=$IFS

#set IFS to $'\n\' - new line
IFS=$'\n'

if [[ -z $@ ]]
  then
  echo "Error: Missing required argument"
  echo
  exit 1
fi

# Put the file glob into an array
file=("$@")

# Now loop through them
for (( i=0 ; i < ${#file[*]} ; i++ ));
do

  if [ -w ${file[$i]} ]; then
     echo ${file[$i]} "  writable" 
  else
     echo ${file[$i]} " NOT writable"
  fi
done

# Reset IFS to its default value
IFS=$sfi

输出

file1.txt writable
file2.txt writable
file3.txt writable

关键是暂时切换IFS(内部字段分隔符)。你必须确保在切换之前存储它,然后在完成它之后将其切换回来,如上所示。

现在,您在文件[]数组中有一个扩展文件列表(带空格转义),然后您可以循环播放。我喜欢这个解决方案是最好的,最容易为用户编程和最简单的方法。

答案 7 :(得分:0)

无需生成shell来查看$?变量,您可以直接对其进行评估。

应该是:

if [ $? -eq 0 ]; then

答案 8 :(得分:0)

你正在运行

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

并且您的交互式shell在脚本获取之前扩展了通配符。您只需在启动时引用第一个参数,如

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

然后,在你的脚本中,引用“$ SRC”,你真正想要带有通配符的东西(即,当你echo $SRC时,而是使用echo "$SRC")并在你的时候不加引号希望扩展通配符。基本上,除非您希望解释元字符,否则始终在可能包含shell元字符的内容周围加上引号。 :)