假设我的输入文件如下所示:
ID1
1 5
6 8
ID2
1 4
5 7
我正在尝试制定一个可以结合这些操作的循环:
如果该行以字母开头:在字段后面保留 '\ n'
如果该行以数字开头:将每个 '\t' 和 '\n' 替换为逗号 (
sed 's / \ t /, / g; s / \ n /, / g '
),除非下一行以字母 (sed 's / \ t /, / g'
)开头
预期输出:
ID1
1, 5, 6, 8
ID2
1, 4, 5, 7
答案1
sed '/^[0-9]/{:a;s/[\t\n ]\+/,/g;N;/\n[A-Z]/!ba;}'
会做的事情。
解释:
/^[0-9]/
将仅匹配以数字开头的行并向其应用命令组
{}
申请的命令组
{:a;s/[\t\n ]\+/,/g;N;/\n[A-Z]/!ba;}
将逐行循环读取并将所有空格、制表符和换行符替换为逗号,直到以字母开头的行。
答案2
您应该能够按如下方式实现:如果当前行以数字开头,则将下一行追加到模式空间中,然后用逗号空格替换空格、制表符和换行符序列:
$ sed '/^[0-9]/{N;s/[ \t\n]\+/, /g}' file
ID1
1, 5, 6, 8
ID2
1, 4, 5, 7
答案3
我会选择awk
,它提供了更多的控制并概括了问题:
awk 'BEGIN{FS="\t"; OFS=","}
/^[^A-Z]/ {for (i=1; i<=NF; i++) {if (!a) a=$i; else a=a OFS $i} next}
{if (a) print a; a=""; print}
END{print a}'
解释
BEGIN{FS="\t"; OFS=","}
将输入字段分隔符设置为制表符,将输出字段分隔符设置为逗号。/^[^A-Z]/ {for (i=1; i<=NF; i++) {if (!a) a=$i; else a=a OFS $i} next}
在不以大写字母开头的行中,将值存储在变量中a
。{if (a) print a; a=""; print}
在其余情况下(即以大写字母开头的行),将存储的值与当前行一起打印。END{print a}
处理整个文件后,使用最后一个块中的值打印最后存储的变量。
查看输出:
$ awk 'BEGIN{FS="\t"; OFS=","}/^[^A-Z]/ {for (i=1; i<=NF; i++) {if (!a) a=$i; else a=a OFS $i} next} {if (a) print a; a=""; print} END{print a}' file
ID1
1,5,6,8
ID2
1,4,5,7
在 sed 中,请记住您始终可以使用-e
选项来组合命令。
答案4
tr -s '\t\nI' ' \n' <<\DATA |\
sed 's/^/I/;s/ */\n/;s/ *[0-9]/,&/g'
ID1
1 5
6 8
ID2
1 4
5 7
DATA
输出
ID1
1, 5, 6, 8
ID2
1, 4, 5, 7
首先
tr
将所有制表符和换行符转换为空格和所有资本都换行。它还会挤压重复次数。这使得事情变得非常简单,因为此时它传递给sed
如下所示的输入:^D [num] [num] [num] [num] [num] ... [num] $
接下来
sed
放置我返回,用换行符替换该行的第一个空格,清除所有尾随空格,然后...在该行剩余的每个空格前面添加一个逗号,就完成了。