bash 条件 getline 与 awk/tr/sed?
bash conditionnal getline with awk/tr/sed?
我正在为此苦苦挣扎,我想将一组行连接成一行 line/row。
我文件的每一行 (titi/toto/tata) 都有 2 或 3 个字段,用“;”分隔
所以我的输入是这样的:
titi1
titi2
titi3
43;75;97
1;2;87
toto1
toto2
toto3
40;50;60
tata1
tata2
tata3
4;5;2
5;3;7
2;5;9
我需要这个输出:
titi1;titi2;titi3;43;75;97
titi1;titi2;titi3;1;2;87
toto1;toto2;toto3;40;50;60
tata1;tata2;tata3;4;5;2
tata1;tata2;tata3;5;3;7
tata1;tata2;tata3;2;5;9
您是否看到前 3 行是信息(toto/tata 等...),在以数字开头的每一行之后都应重复这些信息。
首先,我的输入只有一行数字,所以它是一个 4 乘 4 的分组。所以我在论坛中搜索了我是否找到了一个示例并使用这样的 getline 进行了此操作:
awk '{getline b; getline c; getline d;printf("%s %s %s %s\n",[=14=],b,c,d)}'
但后来我开始有 2 个甚至 3 个 lign with numbers...
所以我正在努力做一个 'conditionnal' 理解它应该在每次看到以数字开头的 lign 时重复前 3 lign。
能否请您尝试以下。
awk '
{
sub(/ +$/,"")
}
/^[a-zA-Z]+/{
if(val && flag){
val=""
}
val=val?val ";" [=10=]:[=10=]
flag=""
next
}
{
flag=1
print val ";" [=10=]
}' Input_file
解决方案 2: 如果您的 Input_file 可以将最后一行设为 tot
等,而您想要也打印它然后使用以下内容。
awk '
{
sub(/ +$/,"")
}
/^[a-zA-Z]+/{
if(val && flag){
val=""
}
val=val?val ";" [=11=]:[=11=]
flag=""
next
}
{
flag=1
print val ";" [=11=]
}
END{
if(val && !flag){
print val
}
}' Input_file
你可以试试这个 awk :
awk -F';' 'NF==1{if(b){a=b=""};a=a[=10=]FS;next}{b=1;[=10=]=a[=10=]}1' infile
更易懂
awk -F ';' '
NF==1 {
if ( b ) {
a = b = ""
}
a = a [=11=] FS
next
}
{
b = 1
[=11=] = a [=11=]
} 1
' infile
这个程序应该是这样的:
awk 'f&&/^[^0-9]/{b="";f=0} /^[^0-9]/{b=b[=10=]";"} /^[0-9]/{print b[=10=];f=1}'
解释:
1. /^[^0-9]/{b=b[=11=]";"}
2. /^[0-9]/{print b[=11=];f=1}
3. f&&/^[^0-9]/{b="";f=0}
- 行不以数字开头:收集输入 (titi,toto,tata)
- 行以数字开头:打印收集的行并
[=12=]
,设置标志
- 行不再以数字开头(已设置标志):重新开始(清除缓冲区和标志)
$ awk -F';' 'NF>1{print s [=10=]; p=1; next} p{s=p=""} {s=s [=10=] FS}' file
titi1;titi2;titi3;43;75;97
titi1;titi2;titi3;1;2;87
toto1;toto2;toto3;40;50;60
tata1;tata2;tata3;4;5;2
tata1;tata2;tata3;5;3;7
tata1;tata2;tata3;2;5;9
使用您的原始脚本 - 请参阅 http://awk.freeshell.org/AllAboutGetline 了解为什么不为此(或大多数其他情况)使用 getline 以及如何在适合这样做的极少数情况下正确调用 getline。
这可能对你有用 (GNU sed):
sed -r '/;/{:a;G;s/([^\n]*)\n(.*)/\n/;s/.//;s/\s*\n/;/g;n;/;/ba;x;z;x};H;d' file
使用保留 space 来存储每条记录的第一部分。当遇到记录的结尾部分时,追加保留 space,重新排列最后一部分以跟在第一部分之后,删除第一个换行符并将剩余的换行符替换为分号。打印记录,如果下一行是记录的结尾部分,则重复。否则,清除保留 space 并将当前行附加到保留 space.
我正在为此苦苦挣扎,我想将一组行连接成一行 line/row。 我文件的每一行 (titi/toto/tata) 都有 2 或 3 个字段,用“;”分隔 所以我的输入是这样的:
titi1
titi2
titi3
43;75;97
1;2;87
toto1
toto2
toto3
40;50;60
tata1
tata2
tata3
4;5;2
5;3;7
2;5;9
我需要这个输出:
titi1;titi2;titi3;43;75;97
titi1;titi2;titi3;1;2;87
toto1;toto2;toto3;40;50;60
tata1;tata2;tata3;4;5;2
tata1;tata2;tata3;5;3;7
tata1;tata2;tata3;2;5;9
您是否看到前 3 行是信息(toto/tata 等...),在以数字开头的每一行之后都应重复这些信息。
首先,我的输入只有一行数字,所以它是一个 4 乘 4 的分组。所以我在论坛中搜索了我是否找到了一个示例并使用这样的 getline 进行了此操作:
awk '{getline b; getline c; getline d;printf("%s %s %s %s\n",[=14=],b,c,d)}'
但后来我开始有 2 个甚至 3 个 lign with numbers... 所以我正在努力做一个 'conditionnal' 理解它应该在每次看到以数字开头的 lign 时重复前 3 lign。
能否请您尝试以下。
awk '
{
sub(/ +$/,"")
}
/^[a-zA-Z]+/{
if(val && flag){
val=""
}
val=val?val ";" [=10=]:[=10=]
flag=""
next
}
{
flag=1
print val ";" [=10=]
}' Input_file
解决方案 2: 如果您的 Input_file 可以将最后一行设为 tot
等,而您想要也打印它然后使用以下内容。
awk '
{
sub(/ +$/,"")
}
/^[a-zA-Z]+/{
if(val && flag){
val=""
}
val=val?val ";" [=11=]:[=11=]
flag=""
next
}
{
flag=1
print val ";" [=11=]
}
END{
if(val && !flag){
print val
}
}' Input_file
你可以试试这个 awk :
awk -F';' 'NF==1{if(b){a=b=""};a=a[=10=]FS;next}{b=1;[=10=]=a[=10=]}1' infile
更易懂
awk -F ';' '
NF==1 {
if ( b ) {
a = b = ""
}
a = a [=11=] FS
next
}
{
b = 1
[=11=] = a [=11=]
} 1
' infile
这个程序应该是这样的:
awk 'f&&/^[^0-9]/{b="";f=0} /^[^0-9]/{b=b[=10=]";"} /^[0-9]/{print b[=10=];f=1}'
解释:
1. /^[^0-9]/{b=b[=11=]";"}
2. /^[0-9]/{print b[=11=];f=1}
3. f&&/^[^0-9]/{b="";f=0}
- 行不以数字开头:收集输入 (titi,toto,tata)
- 行以数字开头:打印收集的行并
[=12=]
,设置标志 - 行不再以数字开头(已设置标志):重新开始(清除缓冲区和标志)
$ awk -F';' 'NF>1{print s [=10=]; p=1; next} p{s=p=""} {s=s [=10=] FS}' file
titi1;titi2;titi3;43;75;97
titi1;titi2;titi3;1;2;87
toto1;toto2;toto3;40;50;60
tata1;tata2;tata3;4;5;2
tata1;tata2;tata3;5;3;7
tata1;tata2;tata3;2;5;9
使用您的原始脚本 - 请参阅 http://awk.freeshell.org/AllAboutGetline 了解为什么不为此(或大多数其他情况)使用 getline 以及如何在适合这样做的极少数情况下正确调用 getline。
这可能对你有用 (GNU sed):
sed -r '/;/{:a;G;s/([^\n]*)\n(.*)/\n/;s/.//;s/\s*\n/;/g;n;/;/ba;x;z;x};H;d' file
使用保留 space 来存储每条记录的第一部分。当遇到记录的结尾部分时,追加保留 space,重新排列最后一部分以跟在第一部分之后,删除第一个换行符并将剩余的换行符替换为分号。打印记录,如果下一行是记录的结尾部分,则重复。否则,清除保留 space 并将当前行附加到保留 space.