2016-12-16 109 views
1

我有* .csv文件。用值,如下基于条件重新排列列

"ASDP02","8801942183589" 

"ASDP06","8801939151023" 

"CSDP04","8801963981740" 

"ASDP09","8801946305047" 

"ASDP12","8801941195677" 

"ASDP05","8801922826186" 

"CSDP08","8801983008938" 

"ASDP04","8801944346555" 

"CSDP11","8801910831518" 

或有时该值如下

"8801989353984","KSDP05" 

"8801957608165","ASDP11" 

"8801991455848","CSDP10" 

"8801981363116","CSDP07" 

"8801921247870","KSDP07" 

"8801965386240","CSDP06" 

"8801956293036","KSDP10" 

"8801984383904","KSDP11" 

"8801944211742","ASDP09" 

只想把数字值(例如8801989353984)总是在第一列中。是否有可能使用BASH脚本?

+2

通常情况下,您不应该在Bash中解析CSV,因为在Bash中编写好的解析器很难,例如,单元格可能包含换行符的一般情况。 –

回答

0

Bash可以做的工作,但AWK可能是一个更好的选择。重新整理文件:

sample.csv:

"ASDP02","8801942183589" 
"8801944211742","ASDP09" 

命令:

awk -F, 'BEGIN{OFS=","}{$1=$1;if(substr($1, 2, length($1) - 2) + 0 == substr($1, 2, length($1) - 2)){print $1,$2}else{print $2,$1}}' sample.csv 
  • substr($1, 2, length($1) - 2) + 0 == substr($1, 2, length($1) - 2)检查列是数字或不是。如果是,打印原线,否则切换列1和列2

输出:

"8801942183589","ASDP02" 
"8801944211742","ASDP09" 
+0

我只想重新排列第一列中列值在csv文件中的列的数值 –

+0

@KaziNymulHaqueKanon现在检查它。我以为他们在不同的文件 – haifzhan

+0

假设有3列,我想获得与以前相同的输出。 “KSDP10”, “20”, “1910427539” “KSDP10”, “20”, “1910427642” “KSDP10”, “20”, “1910427666” “KSDP10”, “20”, “1910427704” “KSDP10 “KSDP10”,“20”,“1910427720” “KSDP10”,“20”,“1910427738” “KSDP10”,“20”,“1910427936” “KSDP10”,“20”,“1910428023” “KSDP10”, “20”, “1910428046” –

0

下面的命令假定在CSV文件中的细胞不包含换行符和逗号。否则,您应该使用Perl,PHP或其他能够正确解析CSV文件的编程语言编写更复杂的脚本。但是Bash肯定不适合这项任务。


的Perl

perl -F, -nle '@F = reverse @F if $F[0] =~ /^"\d+"$/; 
print join(",", @F)' file 

谨防,如果细胞包含换行符,或逗号,使用Perl的Text::CSV的模块,例如。虽然这在Perl中是一项简单的任务,但它超出了当前问题的范围。

该命令用逗号分割输入行(-F,),并将结果存储到@F数组中,每行。如果第一个字段$F[0]与正则表达式匹配,则数组中的项目会颠倒过来。您也可以用这种方式交换项目:($F[0], $F[1]) = ($F[1], $F[0])

最后,用逗号加入数组项,并将打印到标准输出

如果要在原地编辑文件,请使用-i选项:perl -i.backup -F, ...

AWK

awk -F, -vOFS=, '/^"[0-9]+",/ {print; next} 
{ t = $1; $1 = $2; $2 = t; print }' file 

输入和输出字段分隔符与-F,-vOFS=,设置为,

如果行匹配模式/^"[0-9]+",/(该行以“数字”CSV列开头),则脚本将打印该记录并前进到next记录。否则,将执行下一个块。

在下一个块中,它交换前两列并将结果打印到标准输出

如果要在原地编辑文件,请参阅this question的答案。

0

您可以创建一个纯粹的bash脚本生成了你需要的结构等文件:

#!/bin/bash 

csv_file="/path/to/your/csvfile" 
output_file="/path/to/output_file" 

#Optional 
rm -rf "${output_file}" 

readarray -t LINES < <(cat < "${csv_file}" 2> /dev/null) 

for item in "${LINES[@]}"; do 

    if [[ $item =~ ^\"([0-9A-Z]+)\"\,\"([0-9]+)\" ]]; then 
    echo "\"${BASH_REMATCH[2]}\",\"${BASH_REMATCH[1]}\"" >> "${output_file}" 
    else 
    echo "$item" >> "${output_file}" 
    fi 
done 

这工作,即使你的文件是“混”我指的是在正确的格式和其他一些线路行格式不正确。

1

Sed也是你的朋友在这里

输入

cat 41189347 
"ASDP02","8801942183589" 
"ASDP06","8801939151023" 
"CSDP04","8801963981740" 
"ASDP09","8801946305047" 
"ASDP12","8801941195677" 
"ASDP05","8801922826186" 
"CSDP08","8801983008938" 
"ASDP04","8801944346555" 
"CSDP11","8801910831518" 

脚本

sed -E 's/^("[[:alpha:]]+.*"),("[[:digit:]]+")$/\2,\1/' 41189347 

输出

"8801942183589","ASDP02" 
"8801939151023","ASDP06" 
"8801963981740","CSDP04" 
"8801946305047","ASDP09" 
"8801941195677","ASDP12" 
"8801922826186","ASDP05" 
"8801983008938","CSDP08" 
"8801944346555","ASDP04" 
"8801910831518","CSDP11" 
1

awk来救援!

$ awk -F, -v OFS=, '$1~/[A-Z]/{t=$2;$2=$1;$1=t}1' file 

如果第一个字段有字母字符,交换第一列和第二列并打印。