使用不是换行符或零字节的记录定界符对 CSV 进行排序
Sorting CSV with record delimiter that is not a newline or zero byte
我的 CSV 看起来像这样:
"212314334","a sentence with new line in it \n
this is the next line","kajdfad","213",ENDOFLINE\r\n
"212314333","another sentence with new line in it \r\n
this is the next line","kawad","21453",ENDOFLINE\r\n
所以记录中间可能有换行符。文件中也可能有不可打印的字符。记录分隔符为,ENDOFLINE\r\n
.
Linux sort
具有换行符或零字节的记录分隔符,因此我无法使用它。
我尝试使用 awk
和 RS
:
awk -F, 'BEGIN {RS="ENDOFLINE\r\n"} {print }' myFile | sort -t $',' -k 1
但看起来 sort 仍然使用换行符作为分隔符,因为它在中间拆分记录。
有什么解决办法吗?
使用同事建议的可能解决方案进行编辑:
awk -F, 'BEGIN {RS="END\r\n";i=0;} {array[i]=","[=12=]"END\r"; i=i+1}END {n = asort(array, dest);for (i=1; i<=n; i++) dest[i] = substr(dest[i], index(dest[i], )) ; for (i=1; i<=n; i++) print dest[i]}
这与我举的例子不完全一样。这里的排序是根据第二个feild来排序的,第二个feild作为第一个字段附加到排序中,然后被移除。
编辑:在评论中向我指出了原始代码中的一些令人尴尬的错误。这应该可以解决它们。
问题是 sort
不再知道 awk
所做的拆分,因为 awk
的输出与输入没有变化。我的建议是在 awk
;
中完成所有操作
awk -F, 'BEGIN { RS = "ENDOFLINE\r\n" } { lines[] = lines[] [=10=] RT } END { n = asorti(lines, keys); for(i = 1; i <= n; ++i) { printf("%s", lines[keys[i]]) } }'
awk代码是
#!/usr/bin/awk -F, -f
BEGIN {
RS = "ENDOFLINE\r\n"
}
{
lines[] = lines[] [=11=] RT # remember lines by first field in an associative
# array; append lines with duplicate keys.
}
END {
n = asorti(lines, keys) # sort keys; sorted keys end up in the array
# named keys with indices from 1 to n
for(i = 1; i <= n; ++i) { # then walk through the sorted keys
printf("%s", lines[keys[i]]) # and print the lines.
}
}
另一个 awk
awk -F, -vRS="ENDOFLINE/n" '
{a[NR]=[=10=]}END{x=asort(a);while(++i<=x)printf "%xs",a[i] RT}' file
这与 wintermutes 的工作原理类似,但按内容而不是索引排序。
由于您对 $1 进行排序,并且它是从头开始排序的,因此对整行进行排序应该会得到相同的结果。
我假设所有第一个字段的长度都与问题中显示的一样。
我的 CSV 看起来像这样:
"212314334","a sentence with new line in it \n
this is the next line","kajdfad","213",ENDOFLINE\r\n
"212314333","another sentence with new line in it \r\n
this is the next line","kawad","21453",ENDOFLINE\r\n
所以记录中间可能有换行符。文件中也可能有不可打印的字符。记录分隔符为,ENDOFLINE\r\n
.
Linux sort
具有换行符或零字节的记录分隔符,因此我无法使用它。
我尝试使用 awk
和 RS
:
awk -F, 'BEGIN {RS="ENDOFLINE\r\n"} {print }' myFile | sort -t $',' -k 1
但看起来 sort 仍然使用换行符作为分隔符,因为它在中间拆分记录。
有什么解决办法吗?
使用同事建议的可能解决方案进行编辑:
awk -F, 'BEGIN {RS="END\r\n";i=0;} {array[i]=","[=12=]"END\r"; i=i+1}END {n = asort(array, dest);for (i=1; i<=n; i++) dest[i] = substr(dest[i], index(dest[i], )) ; for (i=1; i<=n; i++) print dest[i]}
这与我举的例子不完全一样。这里的排序是根据第二个feild来排序的,第二个feild作为第一个字段附加到排序中,然后被移除。
编辑:在评论中向我指出了原始代码中的一些令人尴尬的错误。这应该可以解决它们。
问题是 sort
不再知道 awk
所做的拆分,因为 awk
的输出与输入没有变化。我的建议是在 awk
;
awk -F, 'BEGIN { RS = "ENDOFLINE\r\n" } { lines[] = lines[] [=10=] RT } END { n = asorti(lines, keys); for(i = 1; i <= n; ++i) { printf("%s", lines[keys[i]]) } }'
awk代码是
#!/usr/bin/awk -F, -f
BEGIN {
RS = "ENDOFLINE\r\n"
}
{
lines[] = lines[] [=11=] RT # remember lines by first field in an associative
# array; append lines with duplicate keys.
}
END {
n = asorti(lines, keys) # sort keys; sorted keys end up in the array
# named keys with indices from 1 to n
for(i = 1; i <= n; ++i) { # then walk through the sorted keys
printf("%s", lines[keys[i]]) # and print the lines.
}
}
另一个 awk
awk -F, -vRS="ENDOFLINE/n" '
{a[NR]=[=10=]}END{x=asort(a);while(++i<=x)printf "%xs",a[i] RT}' file
这与 wintermutes 的工作原理类似,但按内容而不是索引排序。
由于您对 $1 进行排序,并且它是从头开始排序的,因此对整行进行排序应该会得到相同的结果。
我假设所有第一个字段的长度都与问题中显示的一样。