首页 > 解决方案 > shell - 为(已验证的)提供的数字或数字范围迭代循环

问题描述

我需要接受用户的输入(即“读取”)。

此输入可以是单个正数或一个数字范围(格式为 XY )。

然后我需要验证这个输入并在数字范围内执行一个迭代循环(或者在只有 X 的情况下只执行一次)。

例子:

1) 用户提供:“8”或“8-”循环仅运行一次,提供数字 8

2)用户供应:“13-22”

循环运行 11 次(13 到 22),引用数字 13。

3)用户供应:“22-13”

可能应该表现得像上面的#2......但我愿意接受其他干净的方法来验证输入。

到目前为止,我已经完成了以下工作,这对于我所要求的内容来说不是很干净、完整,甚至 100% 正确 - 但它显示了我所追求的努力和想法:

echo "line?"; read -r deleteline
case "$deleteline" in
        ''|*[!0-9\-]*)   echo "not a number";;
        [1-9]|[1-9][0-9]*);;
esac


deleteline_lb=$(echo $deleteline|awk -F "-" '{print $1}')
deleteline_ub=$(echo $deleteline|awk -F "-" '{print $2}')

if [ ! $deleteline_lb = "" ] && [ ! "$deleteline_ub" = "" ]; then
        delete_line_count=1
        delete_line_count=$(expr $deleteline_ub - $deleteline_lb)
        if [ $delete_line_count -le 0 ]; then
                delete_line_count=1
        fi
fi

i=1; while [ $i -le $delete_line_count ]; do
  echo $deleteline_lb $i
  i=$(($i + 1))
done

这需要在 sh 中运行,seq不支持之类的东西 - 所以坚持使用符合 posix 的方法......


为了澄清,我希望执行以下操作(伪代码):1)接受来自用户的输入 2)验证输入是否采用“#”或“#-#”(范围)的形式。3)根据正确/不正确的输入执行选择的(任意)代码路径。4)如果给定单个#,则将其存储到变量以执行未来的操作。5) 如果给定范围,则将两个数字都存储在变量中,以便能够对较低的 # 到较高的数字执行操作。更具体地说,它将是“(较高的#)-(较低的#)+ 1”。因此,如果范围是 12-17,那么我们需要对 12、6x 执行操作。(17 - 12 + 1)。IOW,12-17 包括在内。6) 还需要一种轻松表示数据集是范围还是单个数字的方法,以便可以轻松地分支每个的代码路径。

感谢您的帮助!

更新:

使用我的基本代码,我重新编写了它(朋友的一些意见),基本上想出了这个:

            while true;do
                printf "\\delete lines? [e=Exit] ";read -r deleteline
                case "$deleteline" in
                    [Ee])   break;;
                    *)
                    echo "$deleteline" | egrep -q '^[[:digit:]-]*$' 

                    if [ $? -ne 0 ]; then
                       printf "\\n input is not a number.\\n"
                    else
                        delete_range_start=`echo $deleteline|awk -F "-" '{print $1}'` 
                        delete_range_end=`echo $deleteline|awk -F "-" '{print $2}'` 

                        if [ $delete_range_end -lt $delete_range_start ]; then
                            printf "\\n upper range must be higher than lower range.\\n"
                        else
                            if [ "$delete_range_end" = "" ]; then
                                delete_range_end=$delete_range_start
                            elif [ $delete_range_end -gt $lineNumbers ]; then
                                printf "\\Setting range to last entry\\n"
                            fi
                            break
                        fi  
                    fi
                    ;;
                esac

            done

            deleteline=$delete_range_start
            deleteloop=`expr $delete_range_end - $delete_range_start + 1`

            i=1
            while [ $i -le $deleteloop ]; do
                    # Insert all processing code in here
                    i=`expr $i + 1`
            done    

标签: shellloopsscriptingposix

解决方案


如果你有一个 posix 兼容的 awk,试试这个:

echo "$userInput" | awk -F- '
  ($1+0==$1&&$2+0==$2){
     for(i=$1;($1<$2?i<=$2:i>=$2);)
       print ($1<$2?i++:i--);
     next
  }
  $1+0==$1{
    print $1;
    next
  }
  $2+0==$2{
    print $2;
    next
  }
  ($1+0!=$1&&$2+0!=$2){
    exit 1
  }'

该脚本检查 2 个字段(用 分隔-)是否为数字。如果是这样,它将以升序或降序方式打印这些数字,具体取决于第一个数字是大于还是小于第二个数字。
如果只有一个输入,脚本只会打印它。
如果所有字段都不是数字,则以非零值退出。

该脚本可以是这样的 shell 脚本的验证步骤:

$ cat test.sh
#!/bin/sh
echo -n "range: "
read -r range
validated_input=$(echo "$range" | awk -F- '($1+0==$1&&$2+0==$2){for(i=$1;($1<$2?i<=$2:i>=$2);)print ($1<$2?i++:i--);next}$1+0==$1{print $1;next}$2+0==$2{print $2;next}($1+0!=$1&&$2+0!=$2){exit 1}')
if [ $? -ne 0 ]; then
    echo "Incorrect range" >&2
fi
for i in $validated_input; do
    echo "$i"
done

例子:

$ ./test.sh
range: 10-6
10
9
8
7
6
$ ./test.sh
range: 8-
8
$ ./test.sh
range: hello
Incorrect range

推荐阅读