如果使用absolut路径运行,Bash脚本会出现意外行为

如果使用absolut路径运行,Bash脚本会出现意外行为,bash,undefined-behavior,Bash,Undefined Behavior,因此,我们有一个脚本,它应该根据用户输入更改linux机器的IP。必须验证此用户输入 如果脚本在它所在的目录中运行,那么一切都会按预期运行,但一旦它以绝对路径运行,它似乎在某些点上会中断 我已经尝试使用调试选项set-x,但是输出几乎保持不变 read-p“请输入网络掩码(CIDR格式):”网络掩码 如果[!$(回显“$netmask”| egrep”^([12]?[0-9]?)$”); 然后 subnetok=0 fi 如果[“$subnetok”=“0”]; 然后 echo-e“\033[4

因此,我们有一个脚本,它应该根据用户输入更改linux机器的IP。必须验证此用户输入

如果脚本在它所在的目录中运行,那么一切都会按预期运行,但一旦它以绝对路径运行,它似乎在某些点上会中断

我已经尝试使用调试选项set-x,但是输出几乎保持不变

read-p“请输入网络掩码(CIDR格式):”网络掩码
如果[!$(回显“$netmask”| egrep”^([12]?[0-9]?)$”);
然后
subnetok=0
fi
如果[“$subnetok”=“0”];
然后
echo-e“\033[41m\033[39m子网掩码无效!\033[0m”
睡眠1
返回1
fi
如果脚本在目录中运行,则这是调试输出:

++echo 24
++白鹭“^([12]?[0-9]?)$”
+ '[' '!' 24 ']'
+ '[' '' == 0 ']'
如果脚本以绝对路径运行,则这是调试输出

+++echo 24
+++egrep--颜色=自动“^([12]?[0-9]?)$”
++ '[' '!' 24 ']'
++ '[' 0 == 0 ']'
++echo-e“子网掩码无效”
我希望输出与相同的数字相同

通过使用绝对路径运行,我的意思是./usr/local/script/script.sh,而不是将cd放入/usr/local/script/然后./script.sh

不同之处在于,在一种情况下,您正在执行脚本,而在另一种情况下,您正在寻找脚本的来源。有关更多信息,请参阅

当您运行
/script.sh
时,在点和斜杠之间没有空格,您是在一个新的shell中执行脚本。当您运行
/usr/local/script/script.sh
时,您是在当前shell中寻找脚本。例如,如果您在当前shell中设置了一个别名d不会出现在新的shell中,例如
别名egrep='egrep--color=auto'
。这就是为什么会有差异

有关连的问题:

寻源和执行脚本都将逐行运行脚本中的命令,就像您逐行手动键入这些命令一样

区别在于:

  • 在执行打开新shell的脚本时,在新shell中键入命令,将输出复制回当前shell,然后关闭新shell。对环境的任何更改仅在新shell中生效,并且在新shell关闭后将丢失

  • 编写脚本源代码时,您正在当前shell中键入命令。对环境的任何更改都将生效并保留在当前shell中

如果希望脚本更改当前运行的shell中的环境,请使用source。否则,请使用execute

:

通过使用绝对路径运行,我的意思是./usr/local/script/script.sh,而不是将cd放入/usr/local/script/然后./script.sh

不同之处在于,在一种情况下,您正在执行脚本,而在另一种情况下,您正在寻找脚本的来源。有关更多信息,请参阅

当您运行
/script.sh
时,在点和斜杠之间没有空格,您是在一个新的shell中执行脚本。当您运行
/usr/local/script/script.sh
时,您是在当前shell中寻找脚本。例如,如果您在当前shell中设置了一个别名d不会出现在新的shell中,例如
别名egrep='egrep--color=auto'
。这就是为什么会有差异

有关连的问题:

寻源和执行脚本都将逐行运行脚本中的命令,就像您逐行手动键入这些命令一样

区别在于:

  • 在执行打开新shell的脚本时,在新shell中键入命令,将输出复制回当前shell,然后关闭新shell。对环境的任何更改仅在新shell中生效,并且在新shell关闭后将丢失

  • 编写脚本源代码时,您正在当前shell中键入命令。对环境的任何更改都将生效并保留在当前shell中

如果希望脚本更改当前运行的shell中的环境,请使用source。否则,请使用execute


使用以下命令运行脚本时:

. /usr/local/script/script.sh 
这将使用
命令,该命令在当前shell中运行脚本(相当于
source
)。也就是说,它在交互式shell中运行脚本,而不是在新shell中运行脚本。请参阅:

这(至少)有两个影响:

  • 当前的shell是交互式的,并且显然有一个为
    egrep
    定义的别名,这使得事情有点奇怪。这不是一个真正的问题,只是奇怪而已

  • 当前shell显然已经有了变量
    subnetok
    的定义,它是“0”。这可能是上次以这种方式运行脚本时留下的。这就是问题的原因

主要解决方案是,脚本需要显式初始化
subnetok
,而不仅仅是假设它是未定义的:

subnetok=1
if ...
或者,如果您不需要该变量来执行任何其他操作,您可以跳过它并立即处理该条件:

if [ ! $(echo "$netmask" | egrep  "^([12]?[0-9]?)$") ];    # See below for alternatives
then
    echo -e "\033[41m\033[39m Subnetmask is invalid!\033[0m"
    ...
其他建议:

  • 在不使用
    的情况下运行脚本:

    /usr/local/script/script.sh
    
  • 为脚本指定一个正确的shebang行(如果它还没有),指定bash shell(即
    #!/bin/bash
    #!/usr/bin/env bash

  • 使用更好的方法检查子网的有效性,如:

    if ! echo "$netmask" | grep -Eq  "^[12]?[0-9]?$"
    
    或(仅限bash):

  • 不要使用
    echo-e
    ,因为它不可移植(即使在同一操作系统的不同版本、shell模式等之间)。请改用
    printf
    (我建议对包含反斜杠的字符串使用单引号,因为在某些情况下它们是
    if ! [[ "$netmask" =~ ^[12]?[0-9]?$ ]]
    
    printf '\033[41m\033[39m Subnetmask is invalid!\033[0m'