如何使用bash将行的最后[0-9]{1,9}单元格值移动到最后一行(.csv)

如何使用bash将行的最后[0-9]{1,9}单元格值移动到最后一行(.csv),bash,macos,csv,sed,sh,Bash,Macos,Csv,Sed,Sh,示例.csv: "something","31","null","null","null","null", "something","something","something","142","null","null", "something","something","24","null","null","null", 我希望得到这样的结果: "something","null","null","null","null","31", "something","something","some

示例.csv:

"something","31","null","null","null","null",
"something","something","something","142","null","null",
"something","something","24","null","null","null",
我希望得到这样的结果:

"something","null","null","null","null","31",
"something","something","something","null","null","142",
"something","something","null","null","null","24",
如何使用bash脚本将最后[0-9]{1,9}个数值移动到最后一个单元格中(如果后面的单元格中只有空值)


我试着用sed来做,但没有成功。

这个简短的awk脚本适用于给定的示例:

awk -F',' -v OFS=',' -v pat='^"[0-9]+"$' '{
for(i=NF;i>0;i--)if($i~ pat ){$NF=$i FS;$i="\x98";break}
    sub("\x98,","")
}7' file
简要说明: 这是一个有趣的问题

  • pat
    变量存储我们要移到末尾的正则表达式模式
  • 对于每一行,我们从末尾开始循环并检查模式,以便确保找到最后一个匹配的列
  • 如果我们找到了col,我们将最后一个字段设置为带有逗号的匹配列。(我注意到在每行的末尾总是有一个空字段)。我们将col的值设置为一个不可见的值
    \x98
    ,以便以后可以轻松删除
  • 最后,我们通过
    sub()
测试
此短awk脚本适用于给定示例:

awk -F',' -v OFS=',' -v pat='^"[0-9]+"$' '{
for(i=NF;i>0;i--)if($i~ pat ){$NF=$i FS;$i="\x98";break}
    sub("\x98,","")
}7' file
简要说明: 这是一个有趣的问题

  • pat
    变量存储我们要移到末尾的正则表达式模式
  • 对于每一行,我们从末尾开始循环并检查模式,以便确保找到最后一个匹配的列
  • 如果我们找到了col,我们将最后一个字段设置为带有逗号的匹配列。(我注意到在每行的末尾总是有一个空字段)。我们将col的值设置为一个不可见的值
    \x98
    ,以便以后可以轻松删除
  • 最后,我们通过
    sub()
测试
下面是我在bash中的变体,并给出了解释

raw=( $(cat file) )         # load data to raw array
for item in "${raw[@]}"; {  # loop through raw data
    search=${item//[!0-9]/} # this will give only digits
    # if match found remove it from string by change ,"123", to a comma and paste to the end
    [[ $search ]] && item="${item//,\"$search\",/,}\"$search\"," 
    echo $item # print result
}

下面是我在bash中的变体,并给出了解释

raw=( $(cat file) )         # load data to raw array
for item in "${raw[@]}"; {  # loop through raw data
    search=${item//[!0-9]/} # this will give only digits
    # if match found remove it from string by change ,"123", to a comma and paste to the end
    [[ $search ]] && item="${item//,\"$search\",/,}\"$search\"," 
    echo $item # print result
}


字段值包含分隔符(
)的可能性有多大?如果可能性不大,
awk
将是你最好的选择。遗憾的是,
awk
并不能更好地支持CSV(比如引用的字段)。(编辑:看起来您可以使用
-F',“
作为分隔符?)还可以查看Try
sed-i.bak-E的/^(.*)(“[0-9]+”,)(.*,”,“,”,)$/\1\3\2/”文件
@WiktorStribiżew这并不保证最后的“[0-9]+”已被移动。@Kent它确实被授予了输入完全是OP格式的权限。字段值包含分隔符(
)的可能性有多大?如果可能性不大,
awk
将是你最好的选择。遗憾的是,
awk
并不能更好地支持CSV(比如引用的字段)。(编辑:看起来您可以使用
-F'”、“
作为分隔符?)也可以看看Try
sed-i.bak-E的/^(.*)(“[0-9]+”、(.*”、“null”、)$/\1\3\2/”文件
@WiktorStribiżew这并不保证最后一个“[0-9]+”已被移动。@Kent它确实允许输入是精确的OP格式。@ChristianFröhlich欢迎您。在这里,一个人通过向上投票并接受答案来表示感谢。这可能是因为,如果值是空的“”而不是“null”,那么它将不起作用吗?@ChristianFröhlich也应该起作用,如果空字符串像其他字段一样用双引号括起来。它工作得很好!你能给我一个提示吗,如果我只想移动最后x列中的数字,我需要修改什么部分(前面更多的是我不想移动的id和其他数字)。还是我应该为它提出一个新问题?@ChristianFröhlich很高兴听到这一点。对于您的新需求,您可以尝试扩展
if($i~pat)
->
if($i~pat&&i>NF-x)
,其中
x
是您想要的范围。首先用一个固定的
x
和相应的示例进行尝试。祝你好运。@ChristianFröhlich欢迎你。在这里,一个人通过向上投票并接受答案来表示感谢。这可能是因为,如果值是空的“”而不是“null”,那么它将不起作用吗?@ChristianFröhlich也应该起作用,如果空字符串像其他字段一样用双引号括起来。它工作得很好!你能给我一个提示吗,如果我只想移动最后x列中的数字,我需要修改什么部分(前面更多的是我不想移动的id和其他数字)。还是我应该为它提出一个新问题?@ChristianFröhlich很高兴听到这一点。对于您的新需求,您可以尝试扩展
if($i~pat)
->
if($i~pat&&i>NF-x)
,其中
x
是您想要的范围。首先用一个固定的
x
和相应的示例进行尝试。祝你好运。谢谢,它可以工作,因为我看到脚本正在工作,但几分钟后我需要取消它。也许它不适用于更大的csv文件。谢谢,它可以工作,因为我看到脚本正在工作,但几分钟后我需要取消它。也许它不适用于更大的csv文件。