【问题标题】:Script parameters in BashBash 中的脚本参数
【发布时间】:2026-01-05 00:35:01
【问题描述】:

我正在尝试制作一个应该像这样使用的 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 值。关于如何做到这一点的任何想法?

【问题讨论】:

标签: linux bash shell parameters


【解决方案1】:

您提供给 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 周围的双引号并不总是必需的,但建议使用,因为如果您不将它们放在双引号之间,某些字符串将不起作用。

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      我需要确保我的脚本在各种机器、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 脚本,因为整个操作有几个相互准独立的步骤(我说的是“准”,因为即使每个脚本都可以单独运行,它们通常都一起运行),两天后我发现,我大约一半的同事,作为程序员和所有人,都太好了,无法使用启动器文件,遵循“用法”,或者阅读帮助每次他们做错了什么并且把整个事情弄得一团糟时都会显示出来,以错误的顺序运行带有参数的脚本并抱怨脚本无法正常工作。我是个胆小鬼,我决定彻底检查我所有的剧本,以确保它们不受同事影响。上面的代码段是第一件事。

      【讨论】:

      • 我喜欢这个。我在末尾添加一个部分 ` else echo "Invalid argument: ${!i}" ((i++)) fi `
      【解决方案4】:

      在 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"(一个参数)。始终牢记在 bash 中如何传递和扩展参数,这将为您省去很多麻烦。

      【讨论】:

        【解决方案5】:

        如果您不完全喜欢使用“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 工作原理的快速教程。

        【讨论】:

        • 这似乎是一个可读的解决方案。那么你将如何指定两个标志呢?
        • @Zelphir,您可以指定两个或多个标志,只需在标志后省略“:”即可。例如f:t:vs 将是-f some_f -t some_t -v -s