拆分文件内容并存储到数组中或通过分隔符遍历文件内容

Split file content and store into array or iterate throgh file content by delimeter

我在下面的文件中说 MemberFile.txt。其中包含由分隔符“#”分隔的记录,分隔符“#”从换行符开始并且是该行的单个字符。因此有3条记录。

3RECORDSFILE
#
[FIRSTNAME      ]   FirstName01
[MIDDLENAME     ]   MiddleName01
[LASTNAME       ]   LastName01
[ADDRESS       Q]   AddressOf #001 Pune
[ADDRESS       S]   AddressOf #001
#
[FIRSTNAME      ]   NameFirst02
[MIDDLENAME     ]   MiddleName02
[LASTNAME       ]   LastName02
[ADDRESS       Q]   AddressOf [002
[ADDRESS       N]   Addres Mumbai sOf [002
#
[FIRSTNAME      ]   03FirstName
[MIDDLENAME     ]   MiddleName03
[LASTNAME       ]   LastName03
[ADDRESS       Q]   Address Of 003]

我们如何在没有 cat 整个文件的情况下使用 IFS 遍历记录。我尝试了以下内容但无济于事。看起来它是逐行读取的,而不是指定的 IFS。不知道哪里错了。

#!/bin/bash
while IFS='^#$' read r
do
echo $r
#do something more
done < MemberFile.txt

我尝试使用 awk 的其他选项。指定分隔符并存储到数组中。这也没有产生预期的结果。

arr=($(awk -F='^#$' '{print }' Member.txt))
for i in $arr
do
echo $I
#do something more
done

能不能请你看看哪里不对,指正一下。我很熟悉这个 bash 脚本。我需要对每条记录再次执行一些操作。

使用此 gnu awk 将输入分解为由 #\n:

分隔的记录
awk -v RS='#\n' 'NR>1{print "==================", NR, "================"; print}' file
================== 2 ================
[FIRSTNAME      ]   FirstName01
[MIDDLENAME     ]   MiddleName01
[LASTNAME       ]   LastName01
[ADDRESS       Q]   AddressOf #001 Pune
[ADDRESS       S]   AddressOf #001

================== 3 ================
[FIRSTNAME      ]   NameFirst02
[MIDDLENAME     ]   MiddleName02
[LASTNAME       ]   LastName02
[ADDRESS       Q]   AddressOf [002
[ADDRESS       N]   Addres Mumbai sOf [002

================== 4 ================
[FIRSTNAME      ]   03FirstName
[MIDDLENAME     ]   MiddleName03
[LASTNAME       ]   LastName03
[ADDRESS       Q]   Address Of 003]

您可以对每条记录进行操作,例如使用以下 awk 命令打印所有 FIRSTNAME

awk -v RS='#\n' 'NR>1{print }' file

FirstName01
NameFirst02
03FirstName

如果你确实需要使用数组,你可以这样做:

#!/bin/bash
arry=""
cnt=0
while read -r line
do
        if [[ "$line" == "#" ]]
        then
                cnt=$(($cnt+1))
        else
                arry[$cnt]=${arry[$cnt]}$line"\n"
        fi
done < Member.txt
for ((i=1;i<=$cnt;i++))
do
        echo -e ${arry[$i]}
        # do some other stuff here
done

我们首先在循环中获取 Member.txt 的每一行,并在遇到“#”时增加一个计数器,并使用这个计数器创建每个元素保存每个数据块。然后我们遍历数组并打印出每个块,做任何其他需要的事情。

anubhava 的回答似乎很有用,但如果您需要将输入输入到 bash 变量中,则实际上没有用。完整的过程是将记录读入脚本语言(如 anubhava 所做的),然后用空分隔符打印出记录,然后将记录读入 bash 变量。使用空分隔符,因为您知道文本不会包含空值。一个关键是让read命令使用空字符作为它的分隔符。

第一部分我使用 perl 而不是 awk:

cat Member.txt | perl -e 'use warnings; use strict; my $stdin_raw; { local $/; $stdin_raw = <STDIN>; }; my @records = split(/\n#/m, $stdin_raw);

print(join("\0", @records), "\0");' |而 IFS= 读取 -r -d $'\0' 记录;回声"Got record: $record";完成

但是,由于您所做的只是将“#”替换为 null,因此您可以使用 sed 进行此简单替换:

cat Member.txt | sed 's/^#$/\x00/' | while IFS= read -r -d $'[=11=]' record; do echo "Got record: $record"; done

请注意,需要 IFS= 来防止 read 一次只消耗一个单词。 -d $'[=15=]' 将分隔符设置为空字符。 -r 用于原始模式:它告诉 read 忽略数据中的特殊字符。

但我同意 anubhava 的一件事:脚本语言在文本处理方面比 bash 更强大、更有用。我建议使用 perl 而不是 awk,因为 awk 的规则不像普通的编程语言。尽管用 awk 写了大约一百个脚本,但我从来没有掌握它的窍门。我发现调试 awk 脚本很困难,即使有文档在我面前也是如此。 Awk 是一种简单的语言,当您尝试做复杂的事情时它会变得丑陋。 Perl 有一个更陡峭的初始学习曲线,但它很快就不再像黑魔法了。