解析可选和非可选参数

Parsing optional and not optional arguments

我是 bash 的新手,在阅读并尝试了很多关于如何解析参数的内容之后,我做不到我真正想做的事情,我想解析可选参数而不是可选参数。更具体地说,我想解析 3 个参数,第一个(一个 fastaq 文件)第二个(第二个可选的 fastaq 文件)第三个参数将是一个目录。

my_script.sh -f1 file1.fasta --f2 file2.fasta -d/home/folder1/folder2

my_script.sh -f1 file1.fasta -d /home/folder1/folder2

我尝试过很多方法,但我不知道如何让程序识别何时有两个fasta文件和一个目录,以及何时只有一个fasta文件和一个目录。

有了这个参数,我想把它们保存在变量中,因为它们稍后会被第三方使用。

我试过这个:



for i in "$@"; do
 case $i in
   -f1=|-fasta1=)
     FASTA1="${i#=}"
     shift # past argument=value
     ;;
   -d) DIRECTORY=
  shift 2
     ;;
   -d=|-directory=) DIRECTORY="${i#=}"
   shift # past argument=value
     ;;
   --f2=|-fasta2=) FASTA2="${i#*=}"
    shift # past argument=value
     ;;
   *)
     ;;
 esac
done

但我刚得到这个

scripts_my_first_NGS]$ ./run.sh -f1 fasta.fasta -d /home/folder1
FASTA1  =
DIRECTORY     =
FASTA2     =

基本上,您需要为不与等号一起使用的选项版本添加单独的解析器。

您的 shift 命令也没有用,因为您正在处理 for 循环。所以将其转换为 while [[ $# -gt 0 ]]; do 循环。

我还添加了一些我建议添加的修改。

while [[ $# -gt 0 ]]; do
    case  in
    -f1|-fasta1)
        FASTA1=
        shift
        ;;
    -f1=*|-fasta1=*)
        FASTA1=${1#*=}
        ;;
    -d|-directory)
        DIRECTORY=
        shift
        ;;
    -d=*|-directory=*)
        DIRECTORY=${1#*=}
        ;;
    -f2|fasta2)
        FASTA2=
        shift
        ;;
    -f2=*|-fasta2=*)
        FASTA2=${1#*=}
        ;;
    -*)
        echo "Invalid option: " >&2
        exit 1
        ;;
    --)
        # Do FILES+=("${@:2}") maybe
        break
        ;;
    *)
        # TODO
        # Do FILES+=("") maybe
        ;;
    esac

    shift
done

with-equal 和 non-with-equal 选项的“解析器”也可以统一为 使用辅助函数:

function get_opt_arg {
    if [[  == *=* ]]; then
        __=${1#*=}
        return 1
    elif [[ ${2+.} ]]; then
        __=
        return 0 # Tells that shift is needed
    else
        echo "No argument provided to option ''." >&2
        exit 1
    fi
}

while [[ $# -gt 0 ]]; do
    case  in
    -d|-directory|-d=*|-directory=*)
        get_opt_arg "$@" && shift
        DIRECTORY=$__
        ;;
    -f1|-fasta1|-f1=*|-fasta1=*)
        get_opt_arg "$@" && shift
        FASTA1=$__
        ;;
    -f2|fasta2|-f2=*|-fasta2=*)
        get_opt_arg "$@" && shift
        FASTA2=$__
        ;;
    -*)
        echo "Invalid option: " >&2
        exit 1
        ;;
    --)
        # Do FILES+=("${@:2}") maybe
        break
        ;;
    *)
        # TODO
        # Do FILES+=("") maybe
        ;;
    esac

    shift
done

切勿自行解析命令行选项!

否则请使用 Bash 函数 getopts, if you do not need GNU style long options or use use the GNU program getopt

以下示例使用数组 FASTAFASTA1${FASTA[0]}FASTA2${FASTA[1]}。在 getopts 的情况下,这使得可以多次使用一个选项字符 (-f)。

使用 getopts 只有一个字符的选项:

#! /bin/bash

FASTA=()
DIRECTORY=

while getopts 'f:d:' option; do
  case "$option" in
    f)
      FASTA+=("$OPTARG")
      ;;
    d)
      DIRECTORY="$OPTARG"
      ;;
    *)
      printf 'ERROR: Invalid argument\n' >&2
      exit 1
      ;;
  esac
done
shift $((OPTIND-1))

if [[ -z ${FASTA[0]} ]]; then
  printf 'ERROR: FASTA1 missing\n' >&2
  exit 1
fi

if [[ -z $DIRECTORY ]]; then
  printf 'ERROR: DIRECTORY missing\n' >&2
  exit 1
fi

printf 'FASTA1 = %s\n' "${FASTA[0]}"
printf 'FASTA2 = %s\n' "${FASTA[1]}"
printf 'DIRECTORY = %s\n' "$DIRECTORY"

用法:

run -f file1.fasta -f file2.fasta -d /home/folder1/folder2

getopt 与单字符和 GNU 风格的长选项混合使用:

#! /bin/bash

FASTA=()
DIRECTORY=

options=$(getopt -o d: -l f1: -l f2: -- "$@") || {
  printf 'ERROR: Invalid argument\n' >&2
  exit 1
}
eval set -- "$options"

while true; do
  case "" in
    --f1)
      FASTA[0]=""
      shift 2;;
    --f2)
      FASTA[1]=""
      shift 2;;
    -d)
      DIRECTORY=""
      shift 2;;
    --)
      shift
      break;;
    *)
      break;;
  esac
done

if [[ -z ${FASTA[0]} ]]; then
  printf 'ERROR: FASTA1 missing\n' >&2
  exit 1
fi

if [[ -z $DIRECTORY ]]; then
  printf 'ERROR: DIRECTORY missing\n' >&2
  exit 1
fi

printf 'FASTA1 = %s\n' "${FASTA[0]}"
printf 'FASTA2 = %s\n' "${FASTA[1]}"
printf 'DIRECTORY = %s\n' "$DIRECTORY"

用法:

run --f1 file1.fasta --f2 file2.fasta -d /home/folder1/folder2