【问题标题】:Assign lines to variables with separator in bash在bash中将行分配给带有分隔符的变量
【发布时间】:2017-03-20 14:38:32
【问题描述】:

我有一个从 grep 输出构建的文件,它看起来像这样:

http://google.fr
Pierre google
http://test.fr
--
http://yahoo.com
Jean Yahoo
http://test.fr
--

我为每 3 行创建了一个分隔符“--”。我想将每一行分配给一个变量,例如:

url= "http://google.fr"
name= "Pierre Google"
web= "http://test.fr"

所以我使用 IFS=-- 制作了 bash 脚本,并尝试使用 -d 选项来回显,但我不知道如何将这 3 行分配给每个块的变量。

感谢您的帮助

【问题讨论】:

  • IFS 是一个无序的字符集合; --- 完全相同。同样,-d 的后续参数是一个 single 字符。要准确地解释为什么您使用的 read 不起作用,我们需要查看它,但也很难看出单个 read 在这里如何是正确的工作。 (我想一个人可以使用IFS=$'\n' read -r -d - -a pieces 或类似的,并接受所有其他结果都是空的)。
  • 顺便说一句,url= "http://google.fr" 实际上将http://google.fr 作为命令运行,url 以空值导出到环境。这样的分配将是url="http://google.fr",没有空格。

标签: bash grep ifs


【解决方案1】:

通过一些错误处理,这可能看起来像:

while read -r url && read -r name && read -r web; do
  echo "Read url of $url, name of $name, and web of $web"
  read -r sep || { true; break; } # nothing to read: exit loop w/ successful $?
  if [[ $sep != -- ]]; then
    printf 'Expected separator, but saw: %q\n' "$sep" >&2
    false; break # "--" not seen where expected; exit loop w/ $? indicating failure
  fi
done <in.txt

BashFAQ #1

(顺便说一句——如果你不想去掉前导和尾随空格,我建议用IFS= 清除IFS——要么范围为reads,如while IFS= read -r url &amp;&amp; IFS= read -r name &amp;&amp; IFS= read -r web,要么全局范围为如果没有其他不希望出现副作用的地方,则编写脚本)。

【讨论】:

  • 工作完美,谢谢!我认为这会更困难,但没有:)
【解决方案2】:

您可以将文件预处理为更典型的格式,以使用 IFS 使用 awksed 等实用程序分隔成字段(或变量):

while IFS="|" read -r url name web; do
    echo "$url" "$name" "$web"
done  < <(awk 'BEGIN{RS="--\n"; FS="\n"; OFS="|"} {print $1,$2,$3}' file)

这会保留每行的前导和尾随空格。

如果您想去除前导和尾随空格,请删除 IFS="|"OFS="|" 部分,以便 Bash 去除行:

while read -r url name web; do
    echo "$url" "$name" "$web"
done  < <(awk 'BEGIN{RS="--\n"; FS="\n"} {print $1,$2,$3}' file)

【讨论】:

  • 也很好,如果输入文件有错误,也可以正常工作,谢谢
【解决方案3】:

这应该适用于您的情况

    NR=0
    while read LINE; do
        ((NR++))
        case $NR in
            1)
                URL=$LINE
                    ;;
            2)
                NAME=$LINE
                    ;;
            3)
                WEB=$LINE
                    ;;
            4)
                if [ $LINE = "--" ]; then
                    NR=0
                    #
                    # DO WHAT EVER YOU WANT TO DO WITH YOUR DATA HERE
                    #
                    #
                    echo "$URL;;$NAME;;$WEB"
                else
                    echo "wrong delimiter found \"$LINE\""
                fi
                    ;;
        esac
    done

运行它

script.sh < inputfile.txt

或者只是将 grep 命令的输出通过管道传输到脚本。

【讨论】:

  • 8 分钟太慢了 :-)
  • 一些笔记。首先——全大写的变量名是为对操作系统或shell有意义的变量保留的;应用程序定义的变量名称中应至少包含一个小写字符。请参阅pubs.opengroup.org/onlinepubs/9699919799/basedefs/… 上的相关 POSIX 指南,记住 shell 变量和环境变量共享一个命名空间。
  • 第二——你在[ $LINE = "--" ]中引用了wong的东西; -- 字符串只能在不加引号的情况下对其自身进行评估,但 $LINE 不加引号可以变成零个或多个单词。例如,如果您有一行包含 *,它将被替换为文件名列表,因此您将有类似 [ a.txt b.txt = -- ] 的运行,这不是有效的 test 语法并且会在标准错误。同样,[ = -- ](这将导致空行)会产生错误,因为= 作为一元运算符无效。 [ "$LINE" = -- ] 会避免这种担忧。
  • (另外,我建议对read 使用-r 参数,除非您有特定的理由不这样做:如果没有-r,输入中的反斜杠将被解释为行继续,因此,如果您的名称以反斜杠结尾,那么下一行中的网址将由与名称相同的 read 返回,从而完全排除计数)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-11
  • 1970-01-01
  • 1970-01-01
  • 2015-04-11
  • 2015-05-24
相关资源
最近更新 更多