如何使用Bash getopts命令将所有参数集合在一起
我这里有两个文件需要解析,叫做parse.sh。我必须为它启用可选参数,其中-l代表行,-f代表字段。因此,运行该程序将是./parse.sh-l5-f14 foo。如果没有-l或-f参数,我希望程序默认解析所有行和所有字段。如果指定了-l,我希望它只解析foo的那一行,而且如果也指定了-f,我希望它只解析该字段。我看到getopts通常是这样工作的:如何使用Bash getopts命令将所有参数集合在一起,bash,getopts,Bash,Getopts,我这里有两个文件需要解析,叫做parse.sh。我必须为它启用可选参数,其中-l代表行,-f代表字段。因此,运行该程序将是./parse.sh-l5-f14 foo。如果没有-l或-f参数,我希望程序默认解析所有行和所有字段。如果指定了-l,我希望它只解析foo的那一行,而且如果也指定了-f,我希望它只解析该字段。我看到getopts通常是这样工作的: while getopts "l:f:" opts; do case $opts in l) #code to pars
while getopts "l:f:" opts; do
case $opts in
l) #code to parse that line;;
f) #code to parse that field;;
case
done
但这不是我需要的,因为我希望-l和-f有时一起工作。我在想也许我应该使用getopts将所有选项解析到数组中,然后基于解析该数组编写代码?还有更好的选择吗
这是我的代码:
while getopts "l:f:" opt;
do
options=${opt}${options}
case $opt in
l) lineNumber=$OPTARG ;;
f) fieldNumber=$OPTARG ;;
esac
done
case $options in
f) echo "Parse field $fieldNumber of each line" ;;
l) echo "Parse all fields of line number $lineNumber" ;;
lf | fl) echo "Parse field $fieldNumber of line $lineNumber" ;;
*) echo "Parse all fields of all lines" ;;
esac
当您需要检查其他变量或执行更复杂的操作时,If语句为您提供了更大的灵活性。除非您将[[]]
更改为[]
,否则这在sh
中不起作用
#!/bin/bash
parse()
{
local lines=$1
local fields=$2
local file=$3
# logic goes here
echo "parsing line(s) ${lines} and field(s) ${fields} of file ${file}"
}
lines=all
fields=all
while getopts "l:f:" o; do
case $o in
l) lines=${OPTARG} ;;
f) fields=${OPTARG} ;;
esac
done
shift $((OPTIND-1))
for file; do
parse "${lines}" "${fields}" "${file}"
done
当您需要检查其他变量或执行更复杂的操作时,If语句为您提供了更大的灵活性。除非您将[[]]
更改为[]
,否则这在sh
中不起作用
#!/bin/bash
parse()
{
local lines=$1
local fields=$2
local file=$3
# logic goes here
echo "parsing line(s) ${lines} and field(s) ${fields} of file ${file}"
}
lines=all
fields=all
while getopts "l:f:" o; do
case $o in
l) lines=${OPTARG} ;;
f) fields=${OPTARG} ;;
esac
done
shift $((OPTIND-1))
for file; do
parse "${lines}" "${fields}" "${file}"
done
示例运行:
$ ./t.sh foo.txt bar.txt
parsing line(s) all and field(s) all of file foo.txt
parsing line(s) all and field(s) all of file bar.txt
$ ./t.sh -l 10 foo.txt bar.txt
parsing line(s) 10 and field(s) all of file foo.txt
parsing line(s) 10 and field(s) all of file bar.txt
$ ./t.sh -l 10 -f 5 foo.txt bar.txt
parsing line(s) 10 and field(s) 5 of file foo.txt
parsing line(s) 10 and field(s) 5 of file bar.txt
$ ./t.sh -f 5 foo.txt bar.txt
parsing line(s) all and field(s) 5 of file foo.txt
parsing line(s) all and field(s) 5 of file bar.txt
示例运行:
$ ./t.sh foo.txt bar.txt
parsing line(s) all and field(s) all of file foo.txt
parsing line(s) all and field(s) all of file bar.txt
$ ./t.sh -l 10 foo.txt bar.txt
parsing line(s) 10 and field(s) all of file foo.txt
parsing line(s) 10 and field(s) all of file bar.txt
$ ./t.sh -l 10 -f 5 foo.txt bar.txt
parsing line(s) 10 and field(s) 5 of file foo.txt
parsing line(s) 10 and field(s) 5 of file bar.txt
$ ./t.sh -f 5 foo.txt bar.txt
parsing line(s) all and field(s) 5 of file foo.txt
parsing line(s) all and field(s) 5 of file bar.txt
我做了一个概念脚本。请试一试
#!/bin/bash
PARSE_SPECIFIC_LINE=0
PARSE_SPECIFIC_FIELD=0
shopt -s extglob
while getopts "l:f:" opts; do
case $opts in
l)
if [[ $OPTARG != +([[:digit:]]) || OPTARG -lt 1 ]]; then
echo "Invalid argument to -l: $OPTARG"
exit 1
fi
PARSE_SPECIFIC_LINE=$OPTARG
;;
f)
if [[ $OPTARG != +([[:digit:]]) || OPTARG -lt 1 ]]; then
echo "Invalid argument to -f: $OPTARG"
exit 1
fi
PARSE_SPECIFIC_FIELD=$OPTARG
;;
esac
done
FILES=("${@:OPTIND}")
function parse_line {
local LINE=$1
if [[ -n $LINE ]]; then
if [[ PARSE_SPECIFIC_FIELD -gt 0 ]]; then
read -ra FIELDS <<< "$LINE"
echo "${FIELDS[PARSE_SPECIFIC_FIELD - 1]}"
else
echo "$LINE"
fi
fi
}
for F in "${FILES[@]}"; do
if [[ -e $F ]]; then
if [[ PARSE_SPECIFIC_LINE -gt 0 ]]; then
parse_line "$(sed -n "${PARSE_SPECIFIC_LINE}{p;q}" "$F")"
else
while read -r LINE; do
parse_line "$LINE"
done < "$F"
fi
else
echo "File does not exist: $F"
fi
done
添加-l5
我得到
11604
我做了一个概念脚本。请试一试
#!/bin/bash
PARSE_SPECIFIC_LINE=0
PARSE_SPECIFIC_FIELD=0
shopt -s extglob
while getopts "l:f:" opts; do
case $opts in
l)
if [[ $OPTARG != +([[:digit:]]) || OPTARG -lt 1 ]]; then
echo "Invalid argument to -l: $OPTARG"
exit 1
fi
PARSE_SPECIFIC_LINE=$OPTARG
;;
f)
if [[ $OPTARG != +([[:digit:]]) || OPTARG -lt 1 ]]; then
echo "Invalid argument to -f: $OPTARG"
exit 1
fi
PARSE_SPECIFIC_FIELD=$OPTARG
;;
esac
done
FILES=("${@:OPTIND}")
function parse_line {
local LINE=$1
if [[ -n $LINE ]]; then
if [[ PARSE_SPECIFIC_FIELD -gt 0 ]]; then
read -ra FIELDS <<< "$LINE"
echo "${FIELDS[PARSE_SPECIFIC_FIELD - 1]}"
else
echo "$LINE"
fi
fi
}
for F in "${FILES[@]}"; do
if [[ -e $F ]]; then
if [[ PARSE_SPECIFIC_LINE -gt 0 ]]; then
parse_line "$(sed -n "${PARSE_SPECIFIC_LINE}{p;q}" "$F")"
else
while read -r LINE; do
parse_line "$LINE"
done < "$F"
fi
else
echo "File does not exist: $F"
fi
done
添加-l5
我得到
11604
你的意思是它们应该像
-lf
那样工作吗?但是这对于它们所需的参数来说是不明确的。不,我的意思是如果用户提供-l10和-f2,它将解析文件第10行的第2个字段。如果用户只提供-l10,它将解析该文件所有字段的整行。如果没有提供选项,它将解析整个文件。我明白你的意思。我希望你也尝试过我的脚本。我真的不明白,我有一个类似于你的代码,它工作得非常完美。我有两个带有强制参数的选项,它们都可以省略。我在Debian Jessie(8.9)上使用bash v:4.3.30 getopt v:2.25.2。你的意思是它们应该像-lf
那样工作吗?但是这对于它们所需的参数来说是不明确的。不,我的意思是如果用户提供-l10和-f2,它将解析文件第10行的第2个字段。如果用户只提供-l10,它将解析该文件所有字段的整行。如果没有提供选项,它将解析整个文件。我明白你的意思。我希望你也尝试过我的脚本。我真的不明白,我有一个类似于你的代码,它工作得非常完美。我有两个带有强制参数的选项,它们都可以省略。我在Debian Jessie(8.9)上使用bash v:4.3.30 getopt v:2.25.2。在你的例子中,如果用户输入-f the-l,它将解析行而不是仅解析字段,我认为…在你的例子中,如果用户输入-f the-l,它将解析行而不是仅解析字段,我认为…你的代码有点长。我对shell脚本非常陌生,所以我将采用Adrians的解决方案。您的代码有点长。我对shell脚本非常陌生,所以我将采用Adrians的解决方案。