“论据”与“参数”
首先,让我先解释一下我的意思:
如果函数的参数不包含任何参数
给出以下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
-l
l
-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
}
这适用于所有正常的别名调用l
,ll
等。但一旦我对类似的东西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 中,通过调用工具(不要与getopts
bash 内置工具混淆!)实际上更容易。它实际上将使用 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))
}