如何在 bash 中检查函数的参数是否不包含任何参数

如何在 bash 中检查函数的参数是否不包含任何参数

“论据”与“参数”

首先,让我先解释一下我的意思:

如果函数的参数不包含任何参数

给出以下ls命令:

$ ls -a sub_folder

我称-a sub_folder该函数为参数只有-a我呼唤范围(如解释的那样)这里)。

问题

现在,在我的bash脚本中,如何检查函数的参数是否不包含任何参数?

我想检查一下 中的参数是否$@以 开头-。但我该怎么做呢?
我是 Bash 的新手,因此经验不足,但在 TypeScript 中,我会做类似的事情:

if (args.some(arg => arg.startsWith("-"))) {
  # parameters found
} else {
  # no parameters
}

我想做的事

我实际上想编写自己的ls函数来显示有多少个文件夹和文件(通过)。但这只有在我使用参数count_info调用时才会显示(在我的情况下,我的所有别名都使用选项)。my_ls-ll-l

在我的bashrc我有以下代码:

alias l="my_ls" # the only call with no parameters
alias ll="l -l"
alias la="l -l --almost-all"
alias ls="l -lAsSh"

my_ls () {
  /bin/ls -p --color=always --group-directories-first "$@"
  if [ ! -z "$1" ]; then # check if there were parameters
    count_info
  fi
}

这适用于所有正常的别名调用lll等。但一旦我对类似的东西l subfolder我的功能不再正常工作,因为我的检查[ ! -z "$1" ]失败。

另一个解决方案是简单地测试是否存在参数,-l但我该怎么做呢?尤其是还要-lAsSh考虑参数组合。

答案1

您无法以完全通用的方式检查这一点,因为即使两个使用相同类型的选项解析器的程序仍然会有不同的期望。 (当然,并非所有程序都使用相同的语法。)

例如,--color=always显然是一个接受值的参数(在 getopt_long 语法中)。但是怎么样--color always?一个程序可能会使用“always”作为参数的值,但另一个程序可能会使用“--color”作为布尔参数并将“always”视为独立的位置参数。这两种方式都是指定同一事物的有效方式。

(在 ls 中,“--color”采用选修的值,因此--color always将保留“always”参数作为要列出的文件名……但“--format”需要一个必需的值,如果使用--format long它将使用参数作为选项值。)

因此,您的检查需要准确复制其ls本身的功能 - 您需要列出所有需要值的参数(短参数和长参数)(但不是那些值是可选的参数),如果您看到一个您知道需要取值的选项,您就会知道应该忽略以下项。

(类似地,getopt_long 允许--name缩短为--nam甚至--na,因此您的代码也需要考虑到这一点。它还需要知道单独的--参数处理,并且甚至以破折号开头的参数也不再被视为该点之后的参数。)

事实上,对你来说最简单的方法是实际上使用声称与 Glibc 的 getopt_long() 函数兼容的选项解析库。(但例如,Python 的 argparse 无法工作,因为它处理可选值的方式与 ls 不同。)

/bin/getopt在 bash 中,通过调用工具(不要与getoptsbash 内置工具混淆!)实际上更容易。它实际上将使用 getopt_long() 并对所有参数进行排序,以便您首先整齐地拆分出选项,然后--是 ,最后是非选项参数。

  • 输入:-abT8 one --color two --format three --size four
  • 输出:-a -b -T 8 --color "" --format three --size -- one two four

这样,您只需检查输出中是否有任何内容跟在参数后面--。例如:

#!/bin/bash

short="abcdfghiklmnopqrstuvw:xABCDFGHI:LNQRST:UXZ1"
long="all,almost-all,author,escape,block-size:,ignore-backups,color::,\
directory,dired,classify,file-type,format:,full-time,group-directories\
-first,no-group,human-readable,si,dereference-command-line,dereference\
-command-line-symlink-to-dir,hide:,hyperlink::,indicator-style:,inode,\
ignore:,kibibytes,dereference,numeric-uid-gid,literal,indicator-style:\
,hide-control-chars,show-control-chars,quote-name,quoting-style:,rever\
se,recursive,size,sort:,time:,time-style:,tabsize:,width:,context,help\
,version"
parsed=$(getopt -o "$short" -l "$long" -- "$@") || exit

eval "args=($parsed)"
declare -p args   # print the array's contents

end=0; found=0
for arg in "${args[@]}"; do
        if (( end )); then
                echo "found non-option arg '$arg'"
                exit 1
        elif [[ $arg == "--" ]]; then
                end=1
        fi
done
echo "did not find any non-option args"
exit 0

答案2

我发现了如何getops正确拆分所有参数,最终得到的结果如下:

my_ls () {
  /bin/ls -p --color=always --group-directories-first "$@"

  local OPTIND option
  while getopts ":l" option; do
    if [[ "$option" == "l" ]]; then
      count_info
    fi
  done
  shift $((OPTIND-1))
}

相关内容