bash 中的变量验证(名称和 IP 地址)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13015206/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 03:36:59  来源:igfitidea点击:

Variables validation (name and IP address) in bash

bashvalidationvariables

提问by pi-2r

In the header of my bash script, I have to ask for the user name and his IP address.

在我的 bash 脚本的标题中,我必须询问用户名和他的 IP 地址。

I need to validate entries in this way:

我需要以这种方式验证条目:

  • The user name have to be stored in a namevariable, having his space replaced by underscores. For sample if user hit "Albert Smith", I have to store "Albert_Smith"into my variable name.
  • For the ip address, I need to know if the ip address is consistent with the format. If the format is not good, I must report the error and prompt the user to enter a good ip address to continue the operation.
  • 用户名必须存储在一个name变量中,用下划线替换他的空格。例如,如果用户点击"Albert Smith",我必须存储"Albert_Smith"到我的变量中name
  • 对于ip地址,我需要知道ip地址是否与格式一致。如果格式不好,我必须报错并提示用户输入一个好的ip地址才能继续操作。

I know that i need to use "read", but i don't know to realize my short script (replace and verify). Thank in advance :)

我知道我需要使用“阅读”,但我不知道如何实现我的短脚本(替换并验证)。预先感谢 :)

采纳答案by Janito Vaqueiro Ferreira Filho

I suppose your entries will be line based (ie. the name will be the first line and the IP the second). You can do this:

我想您的条目将基于行(即名称将是第一行,IP 将是第二行)。你可以这样做:

#!/bin/bash

read name    
while [[ ! "$name" =~ '[A-Za-z ]' ]]; do
    read -p "Wrong name format. Re-enter: " name
done

name="${name// /_}"

read ip
while [[ ! "$ip" =~ '^((25[0-5]|2[0-4][0-9]|[01][0-9][0-9]|[0-9]{1,2})[.]){3}(25[0-5]|2[0-4][0-9]|[01][0-9][0-9]|[0-9]{1,2})$' ]]; do
    read -p "Not an IP. Re-enter: " ip
done

The IP regex is rather complex, but it can be decomposed as:

IP正则表达式相当复杂,但可以分解为:

  1. After the start of the string, there must be three groups of "octet" followed by periods, then followed by another "octet" and the end of the string
  2. Octet is either
    1. 250-255,
    2. 200-249
    3. 100-199 (including 000-099, with the explicit 0s before the number)
    4. One or two digits (ie. 0-99)
  1. 在字符串的开始之后,必须有三组“八位字节”后面是句号,然后是另一个“八位字节”和字符串的结尾
  2. 八位字节是
    1. 250-255,
    2. 200-249
    3. 100-199(包括000-099,数字前加0)
    4. 一位或两位数字(即 0-99)

The loop forms will negate !the result of the grep, so it will continue looping while the grepcommand fails. We use printfin order to pass the variable into grep. The -Eflag on the second grepallows the use of extended regular expressions, which include the |OR operator, ()grouping and {}repetitions.

循环形式将否定!的结果grep,因此在grep命令失败时它将继续循环。我们使用printf以将变量传递到grep. 在-E对第二标志grep允许使用扩展正则表达式,其中包括的|OR运算,()分组和{}重复。

Hope this helps a little =)

希望这会有所帮助 =)

回答by German Garcia

Yet another way. Bash only:

又一种方式。仅重击:

#!/bin/bash

read name
name=${name// /_}

read ip
if [[ "$ip" =~ ^([0-9]{1,3})[.]([0-9]{1,3})[.]([0-9]{1,3})[.]([0-9]{1,3})$ ]]
then
    for (( i=1; i<${#BASH_REMATCH[@]}; ++i ))
    do
      (( ${BASH_REMATCH[$i]} <= 255 )) || { echo "bad ip" >&2; exit 1; }
    done
else
      echo "bad ip" >&2
      exit 1;
fi

echo "name:$name"
echo "ip:$ip"

回答by Omriko

not exactly the answer to the question, but for those who love "one liners", an IP validating regex:

不完全是问题的答案,但对于那些喜欢“单行”的人来说,IP 验证正则表达式:

[[ "$IP" =~ ^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$ ]] && echo "valid" || echo "invalid"

回答by Mark Longair

You can do the first part with tr, and the second part with grepand awk:

你可以做的第一部分tr,第二部分与grepawk

#!/bin/sh

echo "Enter a name:"
read FULL_NAME

FULL_NAME_REPLACED="$(echo $FULL_NAME | tr ' ' _)"
echo $FULL_NAME_REPLACED

echo "Enter an IP address:"
read IP_ADDRESS

if echo "$IP_ADDRESS" | egrep -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'
then
    # Then the format looks right - check that each octect is less
    # than or equal to 255:
    VALID_IP_ADDRESS="$(echo $IP_ADDRESS | awk -F'.' ' <=255 &&  <= 255 &&  <= 255 &&  <= 255')"
    if [ -z "$VALID_IP_ADDRESS" ]
    then
        echo "The IP address wasn't valid; octets must be less than 256"
    else
        echo "The IP address was valid"
    fi
else
    echo "The IP address was malformed"
fi

If found the awkexpression used there in this thread. This is an improvement on using grepor sedalone, in that it will also reject octects that are greater than 255, such as 400.400.400.400.

如果找到该线程中awk使用的表达式。这是对使用或单独使用的改进,因为它还会拒绝大于 255 的八位字节,例如.grepsed400.400.400.400

回答by F. Hauri

Yet a newer version

还有一个更新的版本

As a function:

作为一个函数:

ask4nameIp() {
    unset ip name
    local var v1 v2 v3 v4
    while ! [ "$name" ] || ! [ "$ip" ]; do
        printf "Name: %s\r" $name
        read -p Name:\  var
        [ "$var" ] && name=${var// /_}
        printf "IP: %s\r" $ip
        IFS=. read -p IP:\  v{1..5}
        ((${#v1}*${#v2}*${#v3}*${#v4})) &&
            [ -z "${v1//[0-9]}${v2//[0-9]}${v3//[0-9]}${v4//[0-9]}$v5" ] &&
            ((0<=v1&&v1<=255&&0<=v2&&v2<=255&&0<=v3&&v3<=255&&0<=v4&&v4<=255)) &&
           ip=$v1.$v2.$v3.$v4
        [ "$name" ] && [ "$ip" ] ||
            echo something wrong: ${name:-name missing} ${ip:-ip missing}...;
    done;
    printf "Name: '%s'\nIP:   '%s'\n" $name $ip
}

Variables $nameand $ipcould be used outside of function:

变量$name$ip可能的功能之外使用:

$ ask4nameIp ; declare -p name ip
Name: foo bar 23
IP: 10.123.45.67
Name: 'foo_bar_23'
IP:   '10.123.45.67'
declare -- name="foo_bar_23"
declare -- ip="10.123.45.67"

Full procedure with loop until nothing wrong

带循环的完整过程,直到没有问题

Something like this: (Full bash! no pipes, no external tr, awk, sed, ...) Could be tested on bash console with cut'n past, no need to write it in a script file.

像这样:(完整的 bash!没有管道,没有外部 tr、awk、sed,...)可以在 bash 控制台上使用 cut'n 过去进行测试,无需将其写入脚本文件中。

unset name ip; \
while ! [ "$name" ] || ! [ "$ip" ];do
    printf "Name: %s\r" $name;
    read -p Name:\  var;
    [ "$var" ] && name=${var// /_};
    printf "IP: %s\r" $ip;
    read -p IP:\  var;
    iparray=($( IFS=".";echo $var;));
    [ ${#iparray[@]} -eq 4 ] && \
        [ $iparray -ge 0 ] && [ $iparray -le 255 ] && \
        [ ${iparray[1]} -ge 0 ] && [ ${iparray[1]} -le 255 ] && \
        [ ${iparray[2]} -ge 0 ] && [ ${iparray[2]} -le 255 ] && \
        [ ${iparray[3]} -ge 0 ] && [ ${iparray[3]} -le 255 ] && \
        ip=$var;
    [ "$name" ] && [ "$ip" ] || echo something wrong...;
  done; \
printf "Name: '%s'\nIP:   '%s'\n" $name $ip

This look stronger than using bash's regex, but in use, this is a lot lighter.

这看起来比使用 bash 的正则表达式强,但在使用中,这要轻得多。

In use, this will prompt all request with already defined variablesas default and loop until all variables are defined:

在使用中,这将提示所有已定义变量的请求作为默认值并循环,直到所有变量被定义:

  1. unsetall needed variables
  2. main loop untll all needed variables are defined
  3. printrequest and already defined variable (as default) and stay on same line by usine \rinstead of \n
  4. prompt request and readfor answer (The request is rewritedover the one prompted on previous line, on same place).
  5. replace spaces by underscores and define nameif there is something
  6. Repeat operation done for namevariable: printrequest + already defined, than prompt request and readfor anser.
  7. use temporary arrayiparrayfor splitting IP's integer
  8. check: if number of integer == 4 and all are integers, between 0 and 255 incl., then assing IP.
  9. echoa error message unless all variables are defined.
  10. loop
  11. print results
  1. unset所有需要的变量
  2. 主循环直到定义了所有需要的变量
  3. print请求和已经定义的变量(作为默认值)并通过使用\r而不是保持在同一行\n
  4. 提示请求和read回答(请求被重写为在同一位置上一行提示的请求)。
  5. 用下划线替换空格并定义name是否有内容
  6. name变量重复操作:print请求+已定义,而不是提示请求和read分析器。
  7. 使用临时数组iparray拆分 IP 的整数
  8. 检查:如果整数的数量 == 4 并且都是整数,介于 0 和 255 之间,包括,则 assing IP
  9. echo除非定义了所有变量,否则会出现错误消息。
  10. 环形
  11. 打印结果

animated demo

动画演示

回答by Sanjay Yadav

read name
name=`echo $name|tr ' ' _`

read ip
stat=1
if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
    OIFS=$IFS
    IFS='.'
    ip=($ip)
    IFS=$OIFS
    [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 \
        && ${ip[2]} -le 255 && ${ip[3]} -le 255 ]]
    stat=$?
fi