【问题标题】:Split string with literal \n in a for loop在 for 循环中用文字 \n 分割字符串
【发布时间】:2017-06-08 15:58:30
【问题描述】:

请考虑这个字符串:foo\nbar\nbaz

如何使用 \n 作为分隔符来拆分它?

我玩过 IFS,但运气不好。

编辑:我想在 for 循环中拆分它。

好的,我会解释我的情况。

我需要使用存储在 MySQL 数据库中的数据来提供某个配置文件。

我从 TEXT 类型列中获取值。此列中的每条记录可以是空的或多个电子邮件地址 (foo@bar.tld)、域名 (bar.tld) 或包含其子域 (.bar.tld) 的域名的占位符。

根据设计,程序员决定这个字段应该是多行的,因此是分隔符。

我的工作是单独获取这些值并处理它们。所以我遍历这些值并对它们做一些事情。

真正的问题是我得到一个两个字节的分隔符,就像这样:

foo@bar.tld\nfoo.tld\n.foo.tld 所以我不能单独访问每个元素。

希望你现在能理解(英语不是我的母语)。

EDIT2:

现在我正在用这段代码解决问题:

PERMITTED_SENDERS="foo@bar.tld\nfoo.tld\n.foo.tld"

for SENDER in ${PERMITTED_SENDERS//'\n'/ }
do
    if [[ "$SENDER" =~ @ ]]
    then
        printf "\tsender == $SENDER\n"
    elif [[ "$SENDER" =~ ^\. ]]
    then
        printf "\tsender =~ [@|.]$(to_tld_domain $SENDER)\$\n"
    else
        printf "\tsender =~ \@$(to_regex $SENDER)\$\n"
    fi
done

@CharlesDuffy 是 for 循环仍然无法解决这个问题吗?

EDIT3

在彻底阅读 mysql 帮助后,我结束了将 -r 传递给 mysql 命令以获取原始格式的结果。

现在我有了这个:

while IFS='' read -r permitted_sender
do
    # Do stuff
done <<<"$permitted_senders"

【问题讨论】:

  • 该字符串是包含 11 个字符还是 13 个字符?
  • @DavidC.Rankin 它可以是任何长度。我不想在这里使用sed
  • 顺便说一句,考虑运行printf '%q\n' "$var" 并提供其输出——这将使文字与句法的问题变得清晰。
  • @ap,我不确定我是否认为这是一个相关的骗局。这里的 OP 正在尝试迭代片段,而不是将它们逐行拆分。

标签: bash shell


【解决方案1】:

for 循环不适合这项工作。请考虑使用while 循环:

str='foo\nbar\nbaz'

while [[ $str ]]; do            # iterate as long as we have input
  if [[ $str = *'\n'* ]]; then  # if there's a '\n' sequence later...
    first=${str%%'\n'*}         #   put everything before it into 'first'
    rest=${str#*'\n'}           #   and put everything after it in 'rest'
  else                          # if there's no '\n' later...
    first=$str                  #   then put the whole rest of the string in 'first'
    rest=''                     #   and there is no 'rest'
  fi
  echo "Processing piece: $first"
  str=$rest
done

这会正确发出:

Processing piece: foo
Processing piece: bar
Processing piece: baz

也就是说,如果您必须使用for循环:

str='foo\nbar\nbaz'
set -f                                        # disable globbing
printf -v str_literal '%b' "$str"             # replace '\n' with a literal newline
IFS=$'\n' read -r -a pieces <<<"$str_literal" # split on literal newlines
for piece in "${pieces[@]}"; do               # iterate over the pieces
  echo "Processing piece: $piece"
done

请注意,这并非没有副作用——例如,它将用文字制表符替换 \t 序列。我假设这就是你真正想要的,因为你的数据存储使用\n 来引用换行符。

【讨论】:

  • 为了解决这个问题付出了这么大的努力,我真的很尴尬(DAMN)。
  • 别这样,虽然这不完全是“角落案例”,但也不是普通案例。字符串的设置和引用对接下来的所有内容都很重要。很高兴查尔斯能派上用场...:)
  • 我这样做是为了避免这种混乱:SELECT REPLACE(thecolumn,'\n',' ')
  • 如果那就是你想要的,那只是一行bash:str=${str//'\n'/ }
  • 然而,for item in $string 还是有问题的,除非你在它之前运行set -f。请参阅Don't Read Lines With for——当然,您正在迭代字段,但大部分(尽管不是全部)推理仍然适用。
猜你喜欢
  • 2020-06-09
  • 2015-12-04
  • 1970-01-01
  • 2012-06-06
  • 1970-01-01
  • 1970-01-01
  • 2019-01-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多