2

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

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

  • 用户名必须存储在一个name变量中,他的空格用下划线代替。对于用户点击的示例"Albert Smith",我必须存储"Albert_Smith"到我的变量name中。
  • 对于ip地址,我需要知道ip地址是否与格式一致。如果格式不好,我必须报错并提示用户输入好的ip地址才能继续操作。

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

4

6 回答 6

7

还有一种方式。仅重击:

#!/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"
于 2012-10-22T17:35:59.843 回答
5

不完全是问题的答案,但对于那些喜欢“单线”的人来说,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"
于 2014-07-02T11:58:20.503 回答
3

您可以使用 进行第一部分,使用andtr进行第二部分: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'.' '$1 <=255 && $2 <= 255 && $3 <= 255 && $4 <= 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

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

于 2012-10-22T16:23:44.027 回答
1

我想您的条目将基于行(即名称将是第一行,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

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

  1. 在字符串的开始之后,必须有三组“八位位组”后跟句号,然后是另一个“八位位组”和字符串的结尾
  2. 八位字节是
    1. 250-255,
    2. 200-249
    3. 100-199(包括000-099,数字前有显式0)
    4. 一位或两位数(即 0-99)

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

希望这会有所帮助=)

于 2012-10-22T16:21:19.080 回答
0

还有一个更新的版本

作为一个函数:

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
}

变量$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"

带循环的完整过程,直到没有错误

像这样:(完整的 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

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

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

  1. unset所有需要的变量
  2. 主循环直到所有需要的变量都被定义
  3. print请求和已经定义的变量(默认\r)并通过使用而不是保持在同一行\n
  4. 提示请求和read回答(该请求被重写为上一行提示的请求,在同一个地方)。
  5. 用下划线替换空格并定义name是否有东西
  6. name对变量重复操作: printrequest + 已经定义,而不是提示请求和readanser。
  7. 使用临时数组 iparray来分割 IP 的整数
  8. 检查:如果整数个数 == 4 并且都是整数,介于 0 和 255 之间,包括,那么 assing IP
  9. echo除非定义了所有变量,否则会出现错误消息。
  10. 环形
  11. 打印结果

动画演示

于 2012-10-22T16:44:41.887 回答
0
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
于 2015-04-20T12:08:15.993 回答