首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在getopts之后解析脚本参数

在getopts之后解析脚本参数
EN

Unix & Linux用户
提问于 2019-10-28 13:41:15
回答 2查看 1.3K关注 0票数 3

我有一个使用土帽实现交换机的脚本。然而,我在引用下一个论点时遇到了困难。

我的脚本是支持在本地开发环境上备份我们的网站。我添加了一个-p开关来运行一些部署后的步骤。下面是我的语法:

代码语言:javascript
复制
backport -p /path/to/website_backup.sql.gz

因此,在切换之前,我正在测试是否指定了一个文件,并且它是一个正确的文件。因为文件名路径是唯一的参数,我可以假设它是必要的,而且它也是第一个参数($1)。

代码语言:javascript
复制
if [[ $# -eq 0 ]] ; then
  echo 'Specifcy the sql file to backport.';
  exit 0;
fi

if [[ ! -f "$1" ]]; then
  echo "$1 is not a valid file.";
  exit 0;
fi

我找到了这个答案,它演示了如何使用getopts解析开关参数的示例:

代码语言:javascript
复制
while getopts "p" opt; do
  case $opt in
    p) p_post_deploy=true ;; # Handle -a
  esac
done

当然,在实现getopts之后,使用$1作为参数是行不通的。没有开关就没问题。但是,当我添加开关时,它当然是第一个参数,我的脚本正在测试它是否是一个文件。

代码语言:javascript
复制
$ backport -p /path/to/website_backup.sql.gz
-p is not a valid file.

因此,随着开关的引入,我不能依赖在命令中特定位置出现的任何参数。硬编码的$2不能工作,因为如果没有开关,文件名参数就不是第二个参数。我想要一个解决方案,允许我接受一个接一个的开关,并允许我在将来引入新的开关,同时只更新代码来处理新的开关本身(而不必重新洗牌以后可能在引入新开关后移动的参数)。

我查看了unix.stackexchange问题的答案,该问题指导我如何使用getopts解析开关。答案之一$*作为表示其余参数的变量。

代码语言:javascript
复制
if [[ "$*" -eq 0 ]] ; then
  echo 'Specifcy the sql file to backport.';
  exit 0;
fi

然而,当我尝试使用它时,我没有正确地表达语法,并且得到了一个解析错误。

代码语言:javascript
复制
~/scripts/backport: line 14: [[: /d/Downloads/database.sql.gz: syntax error: operand expected (error token is "/d/Downloads/database.sql.gz")

如何在getop之后测试文件名参数?

下面是当前版本的脚本:

代码语言:javascript
复制
$ cat backport
#!/bin/bash

set -e

while getopts "p" opt; do
  case $opt in
    p) p_post_deploy=true ;;
  esac
done

shift $(($OPTIND - 1))
# testing what this variable looks like
printf "Remaining arguments are: %s\n" "$*"

if [[ "$*" -eq 0 ]] ; then
  echo 'Specifcy the sql file to backport.';
  exit 0;
fi

if [[ ! -f "$*" ]]; then
  echo "$* is not a valid file.";
  exit 0;
fi

drush @local.dev sql-drop -y ;
zcat $1 | drush @local.dev sqlc ;
drush @local.dev cr;

if [ ! -z "$p_post_deploy" ] ; then
  echo "Running post-deploy..."
  SCRIPT_PATH=$(dirname "$BASH_SOURCE")
  source "$SCRIPT_PATH/post-deploy"
  post_deploy
fi
EN

回答 2

Unix & Linux用户

回答已采纳

发布于 2019-10-31 14:33:37

我只能为自己的沟通不善而自责,但克莎拉南达已经给出了我在评论中想要的答案。

在使用getopts解析交换机之后

代码语言:javascript
复制
while getopts "p" opt; do
  case $opt in
    p) p_post_deploy=true ;;
  esac
done

这条线

代码语言:javascript
复制
shift "$((OPTIND - 1))"

将从参数列表中删除所有开关,以便您可以再次使用位置参数,就像不使用开关一样。

外壳程序不会自动重置OPTIND。你必须手动重置它。

票数 2
EN

Unix & Linux用户

发布于 2019-10-31 13:19:32

测试构造的应用

代码语言:javascript
复制
if [[ "$*" -eq 0 ]]

是不正确的。-eq用于整型比较,并且假定$*引用所有剩余参数的参数列表,而不是它们的个数,则测试构造必然会产生语法错误,除非此时剩馀参数的列表恰好包含一个元素,该元素还必须表示整数(这不是您想要实现的)。

现在,对于实际的任务,我认为很难将“非选项参数”(它之前没有“宣布”-)和选项参数混为一谈,只要您允许任意的顺序(即,只要您没有指定文件名必须是最后一个)。如果您想使用getopts,您可能只想让文件名也成为一个选项参数,方法是要求将它指定为-f 。然后你可以用

代码语言:javascript
复制
while getopts "pf:" opt; do
  case $opt in
    p)
       p_post_deploy=true
    ;;
    f)
       backportfile=$OPTARG
    ;;
  esac
done

如果没有指定文件名,请让getopts自动抱怨。

代码语言:javascript
复制
./test.sh: option requires an argument -- f

然后,您还可以稍后测试该文件是否存在,如

代码语言:javascript
复制
if [[ ! -f "$backportfile" ]]
then
  echo "$backportfile is not a valid file"
  exit 1
fi
票数 0
EN
页面原文内容由Unix & Linux提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://unix.stackexchange.com/questions/549129

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档