我正在開發一個 Bash 腳本,該腳本需要將零到多個字串作為輸入,但由于串列之前缺少標志,我不確定如何執行此操作。
腳本用法:
script [ list ] [ -t <secs> ] [ -n <count> ]
該串列將零個、一個或多個字串作為輸入。當遇到空格時,在兩個或更多的情況下,它充當字串之間的中斷。這些字串最終將作為grep命令的輸入,所以我的想法是將它們保存在某種陣列中。我目前有-t并且-n作業正常。我曾嘗試查找示例,但無法找到與我想做的類似的任何事情。我的另一個問題是如何在設定標志后忽略字串輸入,以便不接受其他字串。
我當前的腳本:
while getopts :t:n: arg; do
case ${arg} in
t)
seconds=${OPTARG}
if ! [[ $seconds =~ ^[1-9][0-9]*$ ]] ; then
exit
fi
;;
n)
count=${OPTARG}
if ! [[ $count =~ ^[1-9][0-9]*$ ]] ; then
exit
fi
;;
:)
echo "$0: Must supply an argument to -$OPTARG" >&2
exit
;;
?)
echo "Invalid option: -${OPTARG}"
exit
;;
esac
done
編輯:這是一個家庭作業,我不確定引數的順序是否可以改變
uj5u.com熱心網友回復:
請您嘗試以下方法:
#!/bin/bash
# parse the arguments before getopts
for i in "$@"; do
if [[ $i = "-"* ]]; then
break
else # append the arguments to "list" as long as it does not start with "-"
list =("$1")
shift
fi
done
while getopts :t:n: arg; do
: your "case" code here
done
# see if the variables are properly assigned
echo "seconds=$seconds" "count=$count"
echo "list=${list[@]}"
uj5u.com熱心網友回復:
嘗試:
#! /bin/bash -p
# Set defaults
count=10
seconds=20
args=( "$@" )
end_idx=$(($#-1))
# Check for '-n' option at the end
if [[ end_idx -gt 0 && ${args[end_idx-1]} == -n ]]; then
count=${args[end_idx]}
end_idx=$((end_idx-2))
fi
# Check for '-t' option at the (possibly new) end
if [[ end_idx -gt 0 && ${args[end_idx-1]} == -t ]]; then
seconds=${args[end_idx]}
end_idx=$((end_idx-2))
fi
# Take remaining arguments up to the (possibly new) end as the list of strings
strings=( "${args[@]:0:end_idx 1}" )
declare -p strings seconds count
- 基本思想是從右到左而不是從左到右處理引數。
- 該代碼假定唯一可接受的引數順序是問題中給出的順序。特別是,它假設
-tand-n選項如果存在,則它們必須位于末尾,并且如果兩者都存在,則它們必須按該順序排列。 - 它不會嘗試處理與選項結合的選項引數(例如
-t5,而不是-t 5)。如果需要,這可以相當容易地完成。 - 串列中的字串可以以 . 開頭
-。
uj5u.com熱心網友回復:
我的短版
一些備注:
- 而不是回圈遍歷所有引數**,然后
break如果引數由 開始-,我只是使用while回圈。 - 從如何測驗變數是否是 Bash 中的數字?,增加了高效的
is_int測驗功能 - 由于在回圈中完成的任何輸出 (
echo) 都是while getopts ...錯誤的,因此重定向 doSTDERR(>&2) 可以針對整個回圈而不是在每一echo行上重復。 - **注意對所有引數進行回圈可以撰寫
for varname ;do。作為默認引數$@的代表,隱含在回圈中。in "$@"for
#!/bin/bash
is_int() { case ${1#[- ]} in
'' | *[!0-9]* ) echo "Argument '$1' is not a number"; exit 3;;
esac ;}
while [[ ${1%%-*} ]];do
args =("$1")
shift
done
while getopts :t:n: arg; do
case ${arg} in
t ) is_int "${OPTARG}" ; seconds=${OPTARG} ;;
n ) is_int "${OPTARG}" ; count=${OPTARG} ;;
: ) echo "$0: Must supply an argument to -$OPTARG" ; exit 2;;
? ) echo "Invalid option: -${OPTARG}" ; exit 1;;
esac
done >&2
declare -p seconds count args
uj5u.com熱心網友回復:
標準做法是將選項引數放在任何非選項引數或變數引數之前。
getopts本機識別--為選項開關分隔符的結尾。如果您需要傳遞以破折號開頭的引數,-則使用--分隔符,因此getopts停止嘗試攔截選項引數。
這是一個實作:
#!/usr/bin/env bash
# SYNOPSIS
# script [-t<secs>] [-n<count>] [string]...
# Counter of option arguments
declare -i opt_arg_count=0
while getopts :t:n: arg; do
case ${arg} in
t)
seconds=${OPTARG}
if ! [[ $seconds =~ ^[1-9][0-9]*$ ]] ; then
exit
fi
opt_arg_count =1
;;
n)
count=${OPTARG}
if ! [[ $count =~ ^[1-9][0-9]*$ ]] ; then
exit 1
fi
opt_arg_count =1
;;
?)
printf 'Invalid option: -%s\n' "${OPTARG}" >&2
exit 1
;;
esac
done
shift "$opt_arg_count" # Skip all option arguments
[[ "$1" == -- ]] && shift # Skip option argument delimiter if any
# Variable arguments strings are all remaining arguments
strings=("$@")
declare -p count seconds strings
示例用法
字串不以破折號開頭:
$ ./script -t45 -n10 foo bar baz qux
declare -- count="10"
declare -- seconds="45"
declare -a strings=([0]="foo" [1]="bar" [2]="baz" [3]="qux")
字串以破折號開頭,需要--分隔符:
$ ./script -t45 -n10 -- '-dashed string' foo bar baz qux
declare -- count="10"
declare -- seconds="45"
declare -a strings=([0]="-dashed string" [1]="foo" [2]="bar" [3]="baz" [4]="qux")
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/445473.html
