假设我有一个如下所示的文件:
23: a, b, c, d
24: b, d, f
25: c, g
我想得到这样的输出:
23.a
23.b
23.c
23.d
24.b
24.d
24.f
25.c
25.g
当然,仅仅敲出一些东西并不太难,但我想知道是否有一个使用 awk 之类的东西的巧妙的单行代码。
答案1
也许是这样的:
sed 's/: /./;s/\(\([^.]*\.\)[^,]*\), /\1\
\2/;P;D'
这是两行(可以用某些实现\<LF>
替换)。\n
sed
该D
命令是一种实现方式while 循环在sed
。它会删除模式空间的第一行,只要模式空间中还有剩余内容,就会从剩下的内容重新开始。所以上面的内容可以理解为:
do {
- change ": " to "." so we start with "23.a, b, c"
- change "23.x, y, z" to "23.x\n23.y, z"
- print the first line ("23.x"): P
- remove it
} while (pattern space is not empty)
我们不需要第一个s
命令成为循环的一部分,但为了避免这种情况,我们需要使用更详细的循环类型,例如使用标签 ( :
) 和分支命令 ( b
, t
)。
答案2
没关系,我只是记得 awk split 函数,这使得这变得非常简单。
awk -F ":" '{
split($2, ps, ",");
for (i in ps) {
gsub(" ", "",ps[i]);
print $1 "." ps[i];
}
}'
(gsub 正在去除无关的空白。)
不过还是谢谢其他人的回答。
答案3
这是一个 Perl 的:
perl -nle '/(.+?):\s*(.+)/; print "$1.$_" for split(/[,\s]+/,$2);' foo.txt
解释:
perl -nle
:这告诉 Perl 一次一行地解析输入文件 (-n
),执行作为参数给出的脚本,并向每个打印字符串 ( )-e
添加一个新行 ( ) 。\n
-l
/(.+?):\s*(.+)/
:匹配第一个字符,直到第一个冒号后跟 0 个或多个空格 (:\s*
),然后是该行的其余部分。括号是用于捕获模式的 Perl 语法,两个匹配项保存为$1
和$2
。split(/[,\s]*/,$2);
:这将在和/或 空格处分割$2
(上面匹配操作中的第二个匹配模式) ,创建一个匿名数组。,
print "$1.$_" for split()
:迭代通过上面的分割创建的匿名数组,将每个数组成员保存为$_
并将其与$1
(第一步中捕获的第一个模式)和点一起打印.
。
答案4
我认为 awk 单行代码比其他 awk 解决方案更优雅:
awk -F'[:, ]+' '{for(i=2;i<=NF;i++)printf $1"."$i"\n"}' file.in
它利用了 awk 字段分隔符是正则表达式这一事实。