Bash中的脚本参数

137

我正在尝试制作一个应该像这样使用的shell脚本:

ocrscript.sh -from /home/kristoffer/test.png -to /home/kristoffer/test.txt

这个脚本将把图像文件转换成文本文件进行OCR识别。以下是目前我想出的代码:

#!/bin/bash
export HOME=/home/kristoffer
/usr/local/bin/abbyyocr9 -rl Swedish -if ???fromvalue??? -of ???tovalue??? 2>&1

但我不知道如何获取-from-to的值。有什么想法吗?


6
你应该阅读 http://tldp.org/LDP/Bash-Beginners-Guide/html/Bash-Beginners-Guide.html。 - Mehul Rathod
5个回答

154

你提供给bash脚本的参数将会出现在变量$1$2$3中,其中数字表示参数的顺序。$0是指命令本身。

这些参数由空格分隔,因此如果您在命令中提供了-from-to,它们也将出现在这些变量中,所以对于这个命令:

./ocrscript.sh -from /home/kristoffer/test.png -to /home/kristoffer/test.txt

您将获得:

$0    # ocrscript.sh
$1    # -from
$2    # /home/kristoffer/test.png
$3    # -to
$4    # /home/kristoffer/test.txt

可能会更容易省略-from-to,像这样:
ocrscript.sh /home/kristoffer/test.png /home/kristoffer/test.txt

那么您将拥有:

$1    # /home/kristoffer/test.png
$2    # /home/kristoffer/test.txt

不足之处在于你必须按正确的顺序提供它。有一些库可以使解析命令行中的命名参数更加容易,但通常对于简单的Shell脚本,如果没有问题,你应该使用简单的方法。

然后你可以执行以下操作:

/usr/local/bin/abbyyocr9 -rl Swedish -if "$1" -of "$2" 2>&1

$1$2周围加上双引号并非总是必需的,但建议这样做,因为一些字符串如果不用双引号括起来可能无法正常工作。


80

如果您对使用“from”和“to”作为选项名称没有强烈的依赖,那么使用getopts实现这一点相当容易:

while getopts f:t: opts; do
   case ${opts} in
      f) FROM_VAL=${OPTARG} ;;
      t) TO_VAL=${OPTARG} ;;
   esac
done

getopts是一个处理命令行参数并方便地解析它们的程序。

f:t:表示你期望有两个包含值的参数(由冒号表示)。例如,f:t:v表示-v只会被解释为标志。

opts是当前参数存储的位置。在case语句中处理此参数。

${OPTARG}包含参数后面的值。例如,如果您像这样运行脚本:ocrscript.sh -f /home/kristoffer/test.png -t /home/kristoffer/test.txt,则${FROM_VAL}将获取值/home/kristoffer/test.png

正如其他人建议的那样,如果这是您第一次编写bash脚本,您应该阅读一些基础知识。这只是一个关于getopts如何工作的快速教程。


1
这似乎是一个可读的解决方案。那么你如何指定两个标志呢? - Zelphir Kaltstahl
@Zelphir,你可以简单地省略标志后面的“:”来指定两个或更多标志。例如,f:t:vs 将被解释为 -f some_f -t some_t -v -s - h_s

44

使用变量"$1""$2""$3"等来访问参数。要访问所有参数,可以使用"$@",要获取参数的数量,请使用$#(可能有助于检查是否参数过少或过多)。


29

我需要确保我的脚本在不同的机器、shell甚至cygwin版本之间完全可移植。此外,我的同事们是我必须为他们编写脚本的程序员,因此我最终使用了这个:

for ((i=1;i<=$#;i++)); 
do

    if [ ${!i} = "-s" ] 
    then ((i++)) 
        var1=${!i};

    elif [ ${!i} = "-log" ];
    then ((i++)) 
        logFile=${!i};  

    elif [ ${!i} = "-x" ];
    then ((i++)) 
        var2=${!i};    

    elif [ ${!i} = "-p" ]; 
    then ((i++)) 
        var3=${!i};

    elif [ ${!i} = "-b" ];
    then ((i++)) 
        var4=${!i};

    elif [ ${!i} = "-l" ];
    then ((i++)) 
        var5=${!i}; 

    elif [ ${!i} = "-a" ];
    then ((i++)) 
        var6=${!i};
    fi

done;

原因:我也包含了一个 launcher.sh 脚本,因为整个操作有几个步骤是准独立的(我说“准”是因为尽管每个脚本可以单独运行,但通常都会一起运行),在两天内,我发现我的同事中大约一半,都是程序员,他们太聪明了,不需要使用launcher文件,也不会遵循“用法”,或读取每次出错时显示的帮助信息,结果把整个东西搞得一团糟,以错误的顺序运行带参数的脚本,然后抱怨脚本无法正常工作。由于我是个易怒的人,所以决定改进所有的脚本,以确保它们能经受住同事的考验。上面的代码段就是第一步。


2
我喜欢这个。我在结尾添加了一个部分。else echo "无效的参数:${!i}" ((i++)) fi - CJBS

6
在bash中,$1是传递给脚本的第一个参数,$2是第二个参数,依此类推。
/usr/local/bin/abbyyocr9 -rl Swedish -if "$1" -of "$2" 2>&1

所以您可以使用以下内容:
./your_script.sh some_source_file.png destination_file.txt

双引号的解释:

考虑三个脚本:

# foo.sh
bash bar.sh $1

# cat foo2.sh
bash bar.sh "$1"

# bar.sh
echo "1-$1" "2-$2"

现在调用:
$ bash foo.sh "a b"
1-a 2-b

$ bash foo2.sh "a b"
1-a b 2-

当您调用 foo.sh "a b" 时,它将调用 bar.sh a b(两个参数),而使用 foo2.sh "a b" 时,它将调用 bar.sh "a b"(1个参数)。请始终记住在 bash 中如何传递和扩展参数,这将为您节省很多麻烦。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接