AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 729405
Accepted
john smith
john smith
Asked: 2022-12-24 01:19:03 +0800 CST2022-12-24 01:19:03 +0800 CST 2022-12-24 01:19:03 +0800 CST

我可以将两个条件都移动到 1 个条件吗

  • 772

我只编写了几个星期的脚本,我已经设法在这篇文章的底部编写脚本并让它运行。但是,我知道我真正需要做的是将底部的 if 语句条件移动到上面的 if 语句中。所以我需要做这样的条件:

如果文件存在(并且不是空字符串)并且是以下两个之一:(“switchport mode access”或“switchport trunk allowed vlan”)。

我觉得如果我做了类似下面的事情(不确定语法是否正确,但没关系,因为我只是在解释):

     ###### 1 #####        ################ 2 ####################     ######## 3 ########
if ([ ! -z "${prev}" ] && [ "$line" = "switchport access vlan $i" ] || [[ $line =~ $regex ]]);then

然后我担心我不明白它是如何分组的。因此,如果我们将每个条件称为 1、2、3。那么这是否意味着条件 1&2 OR 3。或者这个人条件 1 & (2-OR-3)?就像,有没有一种方法可以通过在要分组的位周围加上括号来消除任何歧义,就像您在数学中所做的那样。正确的做法是什么?

tmpfiles="$PWD/configs/*.tmp"
prev=
for basefile in $tmpfiles
do
while read line
do
    ## get old vlans and interfaces
    for i in "${oldvlans[@]}"
    do
        if ([ ! -z "${prev}" ] && [ "$line" = "switchport access vlan $i" ]);then
            line1="${prev}"
            line2="${line}"
            echo "${line1}"
            echo "${line2}"
        fi
    done
    ### check for lines with "trunk allowed vlans" on and do a no trunk allowed vlan on them
    regex="switchport trunk allowed vlan*"
    if [ ! -z "${prev}" ] && [[ $line =~ $regex ]];then
        line1="${prev}"
        line2="${line}"
        echo "${line1}"
        echo "no ${line2}"
    fi

    prev="${line}"
done < "$basefile" > "$basefile.done"

编辑:我在下面做了一些测试来尝试找出逻辑,因为 stephane 说 () 不是用于分组测试条件,我相信我证明了他/她错了):

$ var1=sumit ; [ -z "var1" ] && ([ "$var1" = "sxxt" ] || [ "$var1" = "sumit" ]);  echo $?
1
$ var1=sumit ; [ -n "var1" ] && ([ "$var1" = "sxxt" ] || [ "$var1" = "sumit" ]);  echo $?
0

所以我认为这是在我想要的地方进行测试的正确方法:

If [condition1] AND if ([condition 2] OR [condition 3] are true). 

但我只是在胡说八道,只需要尝试澄清一下。

bash
  • 2 2 个回答
  • 60 Views

2 个回答

  • Voted
  1. Best Answer
    terdon
    2022-12-24T02:58:20+08:002022-12-24T02:58:20+08:00

    在 bash 中,做你想做的最干净的方法是使用[[ ]]构造而不是更有限的构造[ ]并结合条件:

    if [ ! -z "${prev}" ] && [[ "$line" = "switchport access vlan $i" || "$line" =~ $regex ]];then
    

    哪个工作如你所料:

    $ var1=sumit; [ -z "var1" ] && [[ "$var1" = "sxxt" || "$var1" = "sumit" ]]; echo $?
    1
    $ var1=sumit; [ -n "var1" ] && [[ "$var1" = "sxxt" || "$var1" = "sumit" ]]; echo $?
    0
    

    现在,您确实可以滥用( )在子 shell 中运行测试并检查结果,但它丑陋、复杂且不必要。如果你坚持走这条路,至少要避免使用 subshel​​l 并使用{ }来对命令进行分组:

    $ var1=sumit; [ -z "var1" ] && { [ "$var1" = "sxxt" ] || [ "$var1" = "sumit" ] ;}; echo $?
    1
    $ var1=sumit; [ -n "var1" ] && { [ "$var1" = "sxxt" ] || [ "$var1" = "sumit" ] ;}; echo $?
    0
    
    

    但实际上,如果您使用的是 bash,那就选择[[ ]]. 如果使用 POSIX shell,您可以使用-o:

    $ var1=sumit; [ -z "var1" ] && [ "$var1" = "sxxt" -o  "$var1" = "sumit" ] ; echo $?
    1
    $ var1=sumit; [ -n "var1" ] && [ "$var1" = "sxxt" -o  "$var1" = "sumit" ] ; echo $?
    0
    
    
    • 0
  2. ilkkachu
    2022-12-24T09:34:12+08:002022-12-24T09:34:12+08:00

    关于这部分:

         ###### 1 #####        ################ 2 ####################     ######## 3 ########
    if ([ ! -z "${prev}" ] && [ "$line" = "switchport access vlan $i" ] || [[ $line =~ $regex ]]);then
    

    然后我担心我不明白它是如何分组的。因此,如果我们将每个条件称为 1、2、3。那么这是否意味着条件 1&2 OR 3。或者这个人条件 1 & (2-OR-3)?

    shell 没有命令列表&&中的和的优先级(如上),但从左到右解析它们。所以如果你有,它会被有效地分组为。同样,是。|| A && B || C(A && B) || CA || B && C(A || B) && C

    这与大多数其他编程语言不同, where&&优先于||. 更糟糕的是,在[[ .. ]]条件和算术表达式(例如$(( .. )))内部,Bash 也遵守该优先级。

    所以,这两个是不同的:

    if [[ a = a ]] || [[ a = a ]] && [[ a = b ]]; then
        echo one
    fi
    if [[ a = a    ||    a = a    &&    a = b ]]; then
        echo two
    fi
    

    (当然a = a,a = b这很愚蠢,但可以作为示例。)

    最好避免对条件使用命令列表,而是按照其他人的建议和使用[[ ... ]].

    也就是说,只要您正在运行 Bash 或无论如何都拥有它的其他 shell,因为[[ ... ]]这不是标准功能。在标准的 POSIX shell 中,您只能使用命令列表。


    至于您的代码,我不确定您是否可以通过将这三个条件组合为一个条件来取得很多成就,即使分组正确也是如此:

    if [ ! -z "${prev}" ] && ( [ "$line" = "switchport access vlan $i" ] || [[ $line =~ $regex ]] ); then
    

    (无论您是使用子外壳(foo)还是复合组{ foo;}进行分组)

    主要是因为您拥有它的方式,您必须在${oldvlans[@]}循环中同时执行后两个测试,但实际上只有其中一个取决于循环变量。此外,[ ! -z "$prev" ]条件似乎是while read循环执行任何操作的先决条件,所以为什么不单独使用它。

    我宁愿将这三者分开而不是将它们结合起来:

    while read line
    do
        if [ -z "$prev" ]; then
            continue
        fi
        ## we know "$prev" is non-empty now
    
        ## get old vlans and interfaces
        for i in "${oldvlans[@]}"
        do
            if [ "$line" = "switchport access vlan $i" ]; then
                ...
            fi
        done
        ### check for  "trunk allowed vlans" etc.
        regex="switchport trunk allowed vlan"
        if [[ $line =~ $regex ]]; then
            ...
        fi
    
        prev="${line}"
    done < ...
    

    (或者也许首先检查该行是否匹配switchport access vlan,switchport trunk allowed vlan然后再决定要做什么。)

    请注意,在正则表达式中,n*意味着“零个或多个字母n”,而不是“一个n后跟任何东西”,就像它在 shell 模式中所做的那样。但是在[[ str =~ regex ]]测试中,正则表达式无论如何都没有锚定到字符串的开头/结尾(例如[[ foobar =~ ob ]]是真的),所以你无论如何都不需要尾随的“匹配任何东西”。

    一些其他编程语言也可能提供比 shell 更好的字符串处理工具。

    • 0

相关问题

  • 通过命令的标准输出以编程方式导出环境变量[重复]

  • 从文本文件传递变量的奇怪问题

  • 虽然行读取保持转义空间?

  • `tee` 和 `bash` 进程替换顺序

  • 运行一个非常慢的脚本直到它成功

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve