Linux 使用不同的delimted[再次更新]将delimted字段移动到换行符中
我有一个逗号分隔的txt文件,它必须只有五列,但有些行的列数超过了5列。Linux 使用不同的delimted[再次更新]将delimted字段移动到换行符中,linux,shell,unix,awk,Linux,Shell,Unix,Awk,我有一个逗号分隔的txt文件,它必须只有五列,但有些行的列数超过了5列。 我想把第6到第10行移到一个新行,把第11到第15行移到一个新行,依此类推。 第6、11、16等列使用空格deleimert代替逗号 下面是input.txt 111 1, 2, 3, 4, 5 11 2, 13, 14, 15 5, 16 11, 17, 18, 19, 20 22, 23, 24, 25, 26 22, 27, 28, 29, 21 30, 31, 32, 3333 3, 34 111 1, 2, 3
我想把第6到第10行移到一个新行,把第11到第15行移到一个新行,依此类推。 第6、11、16等列使用空格deleimert代替逗号
下面是
input.txt
111 1, 2, 3, 4, 5
11 2, 13, 14, 15 5, 16 11, 17, 18, 19, 20
22, 23, 24, 25, 26 22, 27, 28, 29, 21 30, 31, 32, 3333 3, 34
111 1, 2, 3, 4, 5
11 2, 13, 14, 15 5, 16
11, 17, 18, 19, 20
22, 23, 24, 25, 26
22, 27, 28, 29, 21
30, 31, 32, 3333 3, 34
下面是Output.txt
111 1, 2, 3, 4, 5
11 2, 13, 14, 15 5, 16 11, 17, 18, 19, 20
22, 23, 24, 25, 26 22, 27, 28, 29, 21 30, 31, 32, 3333 3, 34
111 1, 2, 3, 4, 5
11 2, 13, 14, 15 5, 16
11, 17, 18, 19, 20
22, 23, 24, 25, 26
22, 27, 28, 29, 21
30, 31, 32, 3333 3, 34
在这个问题的当前(第三个)版本中,我们需要计算四个逗号,然后再计算一个实体,后面跟一个空格(不是逗号),然后在该点添加一个换行符。如果是这种情况,则使用:
$ sed 's/\(\([^,]\+,\)\{4\}[[:space:]]\+[[:alnum:]]\+\)[[:space:]]/\1\n/g' input.txt
111 1, 2, 3, 4, 5
11 2, 13, 14, 15 5, 16
11, 17, 18, 19, 20
22, 23, 24, 25, 26
22, 27, 28, 29, 21
30, 31, 32, 3333 3, 34
如果您的sed
支持-r
标志(GNU),则可以稍微改进命令的外观:
sed -r 's/(([^,]+,){4}[[:space:]]+[[:alnum:]]+)[[:space:]]/\1\n/g' input.txt
在OSX上,-r
标志不受-E
支持,应改为:
sed -E 's/(([^,]+,){4}[[:space:]]+[[:alnum:]]+)[[:space:]]/\1\n/g' input.txt
此问题第二版的解决方案 从给出的示例中,每当列以空格而不是逗号结尾时,我们都需要插入一个换行符。如果是这样,那么:
$ sed 's/\>[[:space:]]/\n/g' input.txt
1, 2, 3, 4, 5
12, 13, 14, 15, 16
11, 17, 18, 19, 20
22, 23, 24, 25, 26
22, 27, 28, 29, 21
30, 31, 32, 33, 34
上面的工作原理是查找单词的结尾,sed
表示为\>
,后跟任何类型的空格。然后用换行符替换该空格。后面跟逗号的列将被单独保留
如果我们只想替换第一次出现的,则sed
substitute命令的格式为s/old/new/
,如果我们想替换所有此类出现的,则s/old/new/g
。由于我们希望替换所有引用,因此使用g
。在上面的命令中,“old”部分是\>[[:space:]
,意思是一个单词的结尾后跟任何类型的空格。“new”部分只是表示换行符的\n
sed
还允许在适当位置更改文件:
sed -i 's/\>[[:space:]]/\n/g' input.txt
-i
选项告诉sed
将输入文件更改到位。运行此命令后,将更新input.txt
。尝试:
$ cat f1
1,2,3,4,5
12,13,14,15,16 11,17,18,19,20
22,23,24,25,26 22,27,28,29,21 30,31,32,33,34
$ awk '1' RS=' |\n' f1
1,2,3,4,5
12,13,14,15,16
11,17,18,19,20
22,23,24,25,26
22,27,28,29,21
30,31,32,33,34
用户更新的上述输入解决方案将不起作用
$ cat f2
1, 2, 3, 4, 5
12, 13, 14, 15, 16 11, 17, 18, 19, 20
22, 23, 24, 25, 26 22, 27, 28, 29, 21 30, 31, 32, 33, 34
$ awk '{gsub(/, /,",");gsub(/ /,"\n");gsub(/,/,", ")}1' f2
OR
$ awk '{gsub(/[[:alnum:]] /,"&\n")}1' f2
1, 2, 3, 4, 5
12, 13, 14, 15, 16
11, 17, 18, 19, 20
22, 23, 24, 25, 26
22, 27, 28, 29, 21
30, 31, 32, 33, 34
回答以下评论
gsub(/, /,",") # Substitute comma for comma + space
gsub(/ /,"\n") # So now (field + space + field) is left, substitute space with newline
gsub(/,/,", ") # substitute comma space (as you requested in expected output) for comma (first argument)
我没有时间将下面的脚本从ksh转换为bash,我将此作为一种实践:
#!/bin/ksh
splitline() {
echo $* | IFS=\, read f1 f2 f3 f4 f5
# remove first space
fx=${f5# }
echo ${fx} | read f5a f5b
echo "${f1},${f2},${f3},${f4}, ${f5a}"
if [[ -n "${f5b}" ]]; then
splitline ${f5b}
fi
}
cat input.txt | while read line; do
splitline $line
done
除了第5列和第6列之间的空格、第10列和第11列之间的空格等,
input.txt
中是否可能有任何空格?tr''\n'
我可以看到您更新了input您的input.txt很奇怪:1111、1123333
中的空格被视为数据的一部分,但第5列中的空格必须视为字段分隔符。您确定您的第五列不能有空格作为数据的一部分吗?当一行有5列以上时,您是否总是有5的复数?这将有助于使用IFS=的递归解决方案,并检查第五个字段中是否有空格format@GanzRicanz谢谢你的澄清。看一下修改后的答案。请解释一下awk'{gsub(/,/,“,”);gsub(//,“\n”);gsub(/,/,“,”)}1'
如果列的值像111,11 1123145,1
将输入更新为well@GanzRicanz:是,如果您的输入与第一个解决方案类似,则此操作将不起作用。