如何在shell中将文本输出到文件时保留换行符?

3
我需要将一些值打印到txt文件中。它们的格式如下:
input="Sno;Name;Field1;Field2"

然而所需输出必须是:
Sno-Name
FIELDS ALLOCATED:
Field1
Field2

我这样做:

我是这样做的:

 echo $input | $(awk -F';' '{print $1"-"$2}') >>$txtfile
 echo "FIELDS ALLOCATED:">>$txtfile
 echo "$input" | cut -d';' -f 3,4 >>$txtfile 

这很简单。但问题在于Field1或Field2可能包含换行符。每当出现这种情况时,cut或awk就不会读取第4个字段,并将其视为一个新行。请帮忙解决如何从给定的输入格式中打印两个字段(保留换行符)。


字段数量是固定的吗?你对@tripleee的评论暗示不是。我问这个问题的原因是,否则似乎没有字段分隔符。在你的第一个例子中,你展示了字段之间的分号,但在第二个例子中,你展示了换行符。如果换行符是字段分隔符,并且你不知道有多少个字段,那么你怎么知道一个字段何时结束,下一个字段何时开始呢? - cdarke
@cdarke 输入使用分号作为分隔符,现在我需要将其转换为以新行分隔的输出,同时保留原始的换行符。正如你所看到的,Field1和Field2是相互排列的,因此字段数量不重要。例如:Field1: xxx \n yyy Field2: zzzz \n aaaa 应该打印出 xxx \n yyy \n zzzz \n aaaa - CoderBC
啊,好的,所以输入字段的分隔符是分号。 - cdarke
4个回答

3
如果输入格式正确,您可以收集输入行,直到获得四个字段。
awk -F ';' 'r { $0 = r ORS $0 }
    NR<4 { next }
    {   print $1 "-" $2
        print "FIELDS ALLOCATED:"
        print $3; print $4
        print ""; r="" }' file

“$0 = r” 意味着什么?如果输入可以有多个字段 FIELD1、FIELD2、FIELD3,我们无法确定有多少个字段会怎样? - CoderBC
赋值 $0 = r ORS $0 将当前行与 r 结尾拼接起来,并在前面加上一个换行符,重新计算字段数。因此我们将行收集到 r 中,直到它包含四个字段。 - tripleee
如果您不知道有多少个字段,并且其中一些可能包含换行符,则无法解析您的数据,因为格式是模糊的。也许有一个模式可以帮助我们识别第一个或最后一个字段,但是根据您提供的信息,无法解决变量字段长度的问题。 - tripleee
如果您在打开文件时知道有多少个字段,可以使用 awk -v f=4 '... NF<f { next } ...} - tripleee
虽然如果您知道输入确切地只有一条记录,那么这就很容易了。我写这篇答案的时候假设您有一个以分号分隔的输入文件,其中可能包含多条记录,但如果它始终只有一条记录,那么这应该是可行的。 - tripleee

2

使用FPAT和空的RS,单个gnu-awk可以完成工作:

input=$'Sno;Name;Field1\nFoo;Field2'

awk -v RS= -v FPAT='[^;]+' '{
    printf "%s-%s\nFIELDS ALLOCATED:\n%s\n%s\n", $1, $2, $3, $4}' <<< "$input"

Sno-Name
FIELDS ALLOCATED:
Field1
Foo
Field2

2
这无法应对字段值中嵌入的换行符,因为默认情况下,Awk一次读取一行。 - tripleee
@anubhava 如果两个换行符在一起,这仍然会出错。 - 123
我尝试了相同的命令,复制粘贴,但是它没有起作用,我得到了Sno;Name;Field1-Foo;Field2和下一行:FIELDS ALOOCATED - CoderBC
我刚刚出去了。40分钟后回来后,我会给你提供一个可工作的演示。 - anubhava
1
FPAT仅在gnu-awk 4.0+中可用,可能op没有它。 - 123
显示剩余2条评论

1
只需在awk中更改输入记录分隔符-RS。每个字段周围添加<和>以便更清晰地显示。
编辑:通过在here-doc数据末尾添加';'并添加另一个条件,删除了额外的尾随换行符。
input="Sno;Name;Fie
ld1;Fi
eld2"

awk 'BEGIN{RS=";"} NR==1{f1=$0}; 
     NR==2{print f1 "-" $0; print "FIELDS ALLOCATED:"}
     $0=="\n"{next}
     NR>2{print "<" $0 ">"}' <<< "$input;"

给出:
Sno-Name
FIELDS ALLOCATED:
<Fie
ld1>
<Fi
eld2>

1
为什么field2末尾有一个额外的换行符? - 123
不确定是here-doc还是awk,不过说得好(编辑)。 - cdarke
不是here-string。必须使用awk。 - 123
在你的帮助下我找到了解决方案,谢谢。然而,我使用了一种稍微不同的方法。 - CoderBC

0
input=$'Sno;Name;Field1\nFoo;Field2'

awk 'BEGIN{ RS = "\n\n+" ; FS = ";" } { print $1"-"$2; for(i=3;i<=NF;i++) {print $i}}' <<<"$input"

由于我不知道可以给出多少字段,所以我添加了一个循环,直到NF并将RS更改为空行而不是换行符。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接