【问题标题】:Bash: Conditional Statement Without IF via Grouping Commands and Boolean OperatorsBash:通过分组命令和布尔运算符没有 IF 的条件语句
【发布时间】:2024-01-21 01:47:01
【问题描述】:

我正在尝试从我的 Bash 脚本中消除“if”语法:

N=
MD='title|1.md' 

这按预期工作(打印“1”和“title_1”):

if [ $(echo "$MD" | grep '|') ]; then N="${MD#*|}"; ID=${MD%|*}'_'$N; fi
echo "$N" ; echo "$ID" 

这不是(打印为空):

[[ $(echo $MD | grep '|') ]] && $(N="${MD#*|}" ; ID=${MD%|*}'_'$N)
echo "$N" ; echo "$ID" 

使用bash +x 运行脚本会返回:

+ N=
++ echo 'title|1'
++ grep '|'
+ [[ -n title|1 ]]
++ N=1
++ ID=title_1
+ echo ''

+ echo ''

+ exit

谁能告诉我我做错了什么?谢谢。

【问题讨论】:

  • 为什么你要消除if
  • 我非常感谢 Bash Script 让我们编写代码的方式。有时很难阅读。但它非常非常聪明。在我看来。这就是为什么我通过对命令和布尔运算符进行分组来处理条件语句。
  • 但请注意,foo && bar || baz等同于 if foo; then bar; else baz,这就是为什么替换 if 通常会适得其反。

标签: bash conditional-statements conditional-formatting


【解决方案1】:

命令替换启动一个子shell(在这种情况下,如果有任何输出,捕获的输出将作为命令运行)。你想要一个命令组。

# Skip grep as well
[[ $MD = *\|* ]] && { N=${MD#*|}; ID=${MD%|*}_$N; }

正则表达式可以为您捕获| 的每一侧,无需稍后对MD 进行操作。

[[ $MD =~ (.*)\|(.*) ]] && { N=${BASH_REMATCH[2]}; ID=${BASH_REMATCH[1]}_$N; }

如果您担心可读性,请不要试图将所有内容放在一行中。

if [[ $MD =~ (.*)\|(.*) ]]; then
  N=${BASH_REMATCH[2]}
  ID=${BASH_REMATCH[1]}_$N
fi

【讨论】:

  • 谢谢你,@chepner。现在我明白了 Bash Reference (gnu.org/software/bash/manual/bash.html#Command-Grouping) 中写的内容:“由于列表是在子 shell 中执行的,因此在子 shell 完成后变量赋值不会保持有效。”
  • 不,我根本不关心可读性。我更喜欢一行代码。
【解决方案2】:

您可以根据分隔符|read将字符串拆分为两个变量

$ MD='title|1.md' 
$ IFS=\| read -r ID N <<< "$MD"
$ [ -n "$N" ] && ID="${ID}_${N}"
$
$ echo "$N" ; echo "$ID" 
1.md
title_1.md

【讨论】:

    最近更新 更多