找到包含单个单词的一行并将其与下一行合并
Find a line with a single word and merge it with the next line
我有一个无法解决的 grep 问题。
我有什么。
名字和姓氏列表,例如:
John Doe
Alice Smith
Bob Smith
我的问题。
有时,名字和姓氏是脱节的,例如:
Alice
Smith
Bob Doolittle
Mark
Von Doe //sometimes, there are more than one word on the next line
我想要达到的目标。
将“孤儿”名称与下一行连接起来。
Alice Smith
Bod Doolittle
Mark Von Doe
我已经尝试过的
grep -ozP "^\w+\n\w.+" file | tr '\n' ' '
因此,这里我要求 grep 找到只有一个单词的一行并将其与下一行连接起来,即使下一行有多个单词。
它工作正常,但前提是孤立的单词位于文件的最开头。 如果它出现在第一行下方,grep 不会发现它。所以一个快速而肮脏的解决方案,我会循环遍历文件并在每次通过后删除一行对我来说不起作用。
您可以像这样使用 GNU sed
:
sed -E -i '/^[^[:space:]]+$/{N;s/\n/ /}' file
s='Alice
Smith
Bob Doolittle
Mark
Von Doe //sometimes, there are more than one word on the next line'
sed -E '/^[^[:space:]]+$/{N;s/\n/ /}' <<< "$s"
输出:
Alice Smith
Bob Doolittle
Mark Von Doe //sometimes, there are more than one word on the next line
详情:
/^[^[:space:]]+$/
找到没有白色的行space
{N;s/\n/ /}
- 读取下一行,并将带有此新行的换行符附加到当前模式 space,然后 s/\n/ /
将此换行符替换为 space.
使用awk:
awk '
{f= ? 1 : 0}
v==1{v=0; print; next}
f==0{v=1; printf "%s ", ; next}
1
' file
输出
Alice Smith
Bob Doolittle
Mark Von Doe
如果awk
可以接受:
awk '
NF==1 {printf "%s ",; getline; print; next}
1' names.dat
其中:
NF==1
- 如果当前记录中只有一个 name/field ...
printf / getline / print / next
- 打印字段 #1,读取下一行并打印它,然后跳到下一行
1
- 按原样打印所有其他行
单线:
awk 'NF==1{printf "%s ",;getline;print;next}1' names.dat
这会生成:
Alice Smith
Bob Doolittle
Mark Von Doe //sometimes, there are more than one word on the next line
使用这个 Perl 单行代码:
perl -lane 'BEGIN { $is_first_name = 1; } if ( @F == 1 && $is_first_name ) { @prev = @F; $is_first_name = 0; } else { print join " ", @prev, @F; $is_first_name = 1; @prev = (); }' in_file
Perl 单行代码使用这些命令行标志:
-e
: 告诉 Perl 查找内联代码,而不是在文件中。
-n
:一次循环输入一行,默认分配给 $_
。
-l
: 在执行内联代码之前去除输入行分隔符(默认情况下在 *NIX 上为 "\n"
),并在打印时附加它。
-a
: 在空格或 -F
选项中指定的正则表达式上将 $_
拆分为数组 @F
。
这可能对你有用 (GNU sed):
sed -E 'N;s/^(\S+)\n/ /;P;D' file
追加下一行。
如果模式 space 中的第一行仅包含一个单词,请将以下换行符替换为 space。
Print/delete 第一行并重复。
我有一个无法解决的 grep 问题。
我有什么。 名字和姓氏列表,例如:
John Doe
Alice Smith
Bob Smith
我的问题。 有时,名字和姓氏是脱节的,例如:
Alice
Smith
Bob Doolittle
Mark
Von Doe //sometimes, there are more than one word on the next line
我想要达到的目标。 将“孤儿”名称与下一行连接起来。
Alice Smith
Bod Doolittle
Mark Von Doe
我已经尝试过的
grep -ozP "^\w+\n\w.+" file | tr '\n' ' '
因此,这里我要求 grep 找到只有一个单词的一行并将其与下一行连接起来,即使下一行有多个单词。
它工作正常,但前提是孤立的单词位于文件的最开头。 如果它出现在第一行下方,grep 不会发现它。所以一个快速而肮脏的解决方案,我会循环遍历文件并在每次通过后删除一行对我来说不起作用。
您可以像这样使用 GNU sed
:
sed -E -i '/^[^[:space:]]+$/{N;s/\n/ /}' file
s='Alice
Smith
Bob Doolittle
Mark
Von Doe //sometimes, there are more than one word on the next line'
sed -E '/^[^[:space:]]+$/{N;s/\n/ /}' <<< "$s"
输出:
Alice Smith
Bob Doolittle
Mark Von Doe //sometimes, there are more than one word on the next line
详情:
/^[^[:space:]]+$/
找到没有白色的行space{N;s/\n/ /}
- 读取下一行,并将带有此新行的换行符附加到当前模式 space,然后s/\n/ /
将此换行符替换为 space.
使用awk:
awk '
{f= ? 1 : 0}
v==1{v=0; print; next}
f==0{v=1; printf "%s ", ; next}
1
' file
输出
Alice Smith
Bob Doolittle
Mark Von Doe
如果awk
可以接受:
awk '
NF==1 {printf "%s ",; getline; print; next}
1' names.dat
其中:
NF==1
- 如果当前记录中只有一个 name/field ...printf / getline / print / next
- 打印字段 #1,读取下一行并打印它,然后跳到下一行1
- 按原样打印所有其他行
单线:
awk 'NF==1{printf "%s ",;getline;print;next}1' names.dat
这会生成:
Alice Smith
Bob Doolittle
Mark Von Doe //sometimes, there are more than one word on the next line
使用这个 Perl 单行代码:
perl -lane 'BEGIN { $is_first_name = 1; } if ( @F == 1 && $is_first_name ) { @prev = @F; $is_first_name = 0; } else { print join " ", @prev, @F; $is_first_name = 1; @prev = (); }' in_file
Perl 单行代码使用这些命令行标志:
-e
: 告诉 Perl 查找内联代码,而不是在文件中。
-n
:一次循环输入一行,默认分配给 $_
。
-l
: 在执行内联代码之前去除输入行分隔符(默认情况下在 *NIX 上为 "\n"
),并在打印时附加它。
-a
: 在空格或 -F
选项中指定的正则表达式上将 $_
拆分为数组 @F
。
这可能对你有用 (GNU sed):
sed -E 'N;s/^(\S+)\n/ /;P;D' file
追加下一行。
如果模式 space 中的第一行仅包含一个单词,请将以下换行符替换为 space。
Print/delete 第一行并重复。