在 Bash 中编写脚本参数

我正在尝试创建一个 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的值。有什么办法吗?

191453 次浏览

在 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 中传递和展开的,这将为您省去很多麻烦。

您提供给 bashscript 的参数将出现在变量 $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的双引号并不总是必要的,但是建议使用,因为如果不将一些字符串放在双引号之间,它们将不起作用。

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

如果您没有完全使用“ 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:指定需要2个包含值的参数(由冒号表示)。像 f:t:v这样的东西说 -v只会被解释为一个标志。

opts是存储当前参数的地方。 case语句是处理这个问题的地方。

${OPTARG}包含参数后面的值。例如,如果您像下面这样运行脚本,${FROM_VAL}将得到值 /home/kristoffer/test.png:

ocrscript.sh -f /home/kristoffer/test.png -t /home/kristoffer/test.txt

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

我需要确保我的脚本在各种机器、 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脚本,因为整个操作有几个步骤是相互准独立的(我说的是“准”,因为即使每个脚本可以单独运行,它们通常也是一起运行的) ,两天后我发现,我的大约一半的同事,作为程序员和所有人,都太优秀了,不能使用启动程序文件,遵循“用法”,或者阅读 HELP,每次他们做错了什么,他们就把整个事情搞得一团糟,用错误的顺序运行带有参数的脚本,并抱怨脚本不能正常工作。作为脾气暴躁的我,我决定彻底检查我所有的脚本,以确保它们是同事证明。上面的代码段是第一件事。