手头的文件列出了数千名用户的名称、凭据、角色和权限。它以 .xls 的形式传递给我,但行和列没有以正确的形式排列。我已经使用 awk 和 sed 重新格式化了原始文件,现在我有许多具有一致格式的行,如下所示:
ID ;email ;role ;privilege ;access-to
8charID1 ;[email protected] ;usr ;read ;finance ;HR ;accounting; dev
8charID2 ;[email protected] ;mgr ;rwx ;finance
8charID3 ;[email protected] ;usr ;rx ;marketing ;dev ;doc
.
.
n x 1,000 number of users
但我被困在下一步了。
目标:重新打印行,以便在存在多个访问字段(如第 1 行或第 3 行)的情况下,根据访问字段的数量重新打印所有前面的字段,并将访问字段重新排序为单个列。
ID ;email ;role ;privilege ;access-to
abcuser1 ;[email protected] ;usr ;read ;finance
abcuser1 ;[email protected] ;usr ;read ;HR
abcuser1 ;[email protected] ;usr ;read ;accounting
abcuser1 ;[email protected] ;usr ;read ;dev
user2def ;[email protected] ;mgr ;rwx ;finance
zyxuser3 ;[email protected] ;usr ;rx ;marketing
zyxuser3 ;[email protected] ;usr ;rx ;dev
zyxuser3 ;[email protected] ;usr ;rx ;publication
.
.
.
n x 1,000 number of users
答案1
awk -F';' -v OFS=';' '
{ for (i=5; i<=NF; i++) print $1,$2,$3,$4,$i }
' file
输出
ID ;email ;role ;privilege ;access-to
8charID1 ;[email protected] ;usr ;read ;finance
8charID1 ;[email protected] ;usr ;read ;HR
8charID1 ;[email protected] ;usr ;read ;accounting
8charID1 ;[email protected] ;usr ;read ; dev
8charID2 ;[email protected] ;mgr ;rwx ;finance
8charID3 ;[email protected] ;usr ;rx ;marketing
8charID3 ;[email protected] ;usr ;rx ;dev
8charID3 ;[email protected] ;usr ;rx ;doc
答案2
以下是与 Glenn 的解决方案相同的基本思想,但使用 Perl 语言:
$ perl -F";" -lane '$"=";";print "@F[0..3];", $_ for @F[4..$#F]' file
ID ;email ;role ;privilege ;access-to
8charID1 ;[email protected] ;usr ;read ;finance
8charID1 ;[email protected] ;usr ;read ;HR
8charID1 ;[email protected] ;usr ;read ;accounting
8charID1 ;[email protected] ;usr ;read ; dev
8charID2 ;[email protected] ;mgr ;rwx ;finance
8charID3 ;[email protected] ;usr ;rx ;marketing
8charID3 ;[email protected] ;usr ;rx ;dev
8charID3 ;[email protected] ;usr ;rx ;doc
解释
-a
:使 perl 的行为类似于awk
,自动将每一行分割成空格上的字段(默认情况下,请参阅-F
)并将它们保存在@F
数组中。-e
:让您在命令行上给出脚本。-n
:逐行读取输入文件。-l
print
:删除尾随换行符并为每个调用添加换行符。-F
: 就像awk
,输入字段分隔符。在这里,我们将其设置为;
。
诚然,该脚本有点神秘,但算法非常简单:打印前四个字段,并对每个字段重复 >4。
$"=";"
:特殊变量$"
是列表分隔符。这是在打印数组时在数组的每个元素之间打印的。在这里,我将其设置为;
,这样我们就可以根据需要打印字段列表。@F[0..3]
:这是一个数组切片。它是数组的前 4 个元素@F
(;
当前行的 - 分隔字段)@F[4..$#F]
:另一个数组切片。这个是从第 5 个元素@F
到最后一个元素($#array
是 Perl 中数组的最大索引)。
整个 print 命令只是惯用的 Perl 命令:
## For each element of the array slice
foreach $field (@F[4..$#F]){
## print the first 4 fields and a ';', The fields
## are printed separated by ";" because of the $" above.
print "@F[0..3];";
## In the golfed version, the $_ is equivalent to $field here
print "$field\n"
}