![我有 Unix 脚本问题](https://linux22.com/image/153150/%E6%88%91%E6%9C%89%20Unix%20%E8%84%9A%E6%9C%AC%E9%97%AE%E9%A2%98.png)
输入 - -
System:root,bin,user,saaa
显示输出----
System,root
System,bin
System,user
System,says
如何获得这个输出?
答案1
我建议您使用perl
,但由于您指定了 shell 脚本...
第 1 步:根据角色将台词分成两部分:
。使用cut
命令或${parameter#word}
and${parameter%word}
结构。
步骤 2:根据角色将行的第二部分分成多个部分,
。使用该awk
命令 - 它应该告诉您您将拥有多少块(我不是专家awk
,所以我不确定这是否会按照我设想的方式工作。)
步骤 3:循环浏览步骤 2 中获得的各个部件,将它们附加到步骤 1 中的第一个部件上,然后打印。
答案2
如果我们可以假设您的输入行恰好包含一个冒号 ( :
),,
冒号之前不能出现逗号 ( ),并且逗号和冒号都不能成为提取的子字符串的一部分(甚至没有转义),那么一个简单的awk
脚本可能是足够的:
$ printf '%s\n' 'System:one,two,three' |
awk -v FS=':|,' '{ for (i=2;i<=NF;i++) { print $1","$i } }'
输出:
System,one
System,two
System,three
字段分隔符FS
是一个扩展的正则表达式,它将在每个字符:
或上进行分割,
。
相反,如果您想要选择第一个冒号(可能包括逗号)之前的所有内容作为第一个输出字段,并在任何逗号处分割任何输入行的其余部分(假设没有逗号打算保留为任何的一部分)子字符串(甚至没有转义)),您可以求助于 shell 功能,如中所建议的海米的回答:
$ printf '%s\n' 'System:one,two,three' |
while IFS= read -r rem; do # IFS= to preserve blank characters
first=${rem%%:*} # Remove from the first ':' on
rem=${rem#"$first"} # Remove first from the beginning of rem
rem=${rem#:} # Strip the remaining ':' at rem's beginning
while test "$rem"; do # Exit when rem is empty
second=${rem%%,*} # Remove from the first ',' on
rem=${rem#"$second"} # Remove second from the beginning of rem
rem=${rem#,} # Strip the remaining ',' at rem's beginning
printf '%s\n' "$first,$second"
done
done
只要确保您理解使用 shell 循环处理文本的注意事项。
或者,使用 GNU sed
:
$ printf '%s\n' 'System:one,two,three' |
sed -n '
:l1
s/^[^:]*:\n//g;
t l2;
s/^\([^:]\{1,\}\):\([^,\n]\{1,\}\)*,\{0,1\}\(.*\)$/\1:\3\n\1,\2/;
t l1;
q;
:l2 p;
'
这里,分支 ( t
) 到标签 ( l1
) 用于通过循环处理每一行输入。一次一个,第一个:
和第一个后续之间的子字符串,
作为新行附加到模式空间,并连接在第一个之前的子字符串之后:
。当没有更多的子字符串可提取时,原始字符串的剩余部分将被删除,模式空间将被打印并且程序退出。
(对于 GNUsed
版本 >= 4.6,您可以通过使用选项调用它来逐步查看正在发生的情况--debug
)。
请注意,使用\n
内部括号表达式来匹配(此处为否定匹配)<newline>
字符是非标准的:POSIX 规定<backslash>
在该上下文中将失去任何特殊含义。