【问题标题】:Bash: Parse CSV and edit cell valuesBash:解析 CSV 并编辑单元格值
【发布时间】:2017-07-10 02:35:20
【问题描述】:

我是 bash 脚本的新手 我有以下 CSV

输入

ID Location Way Day DayTime NightTime StandNo
1  abc      Up  mon 6.00     18.00    6

预期输出

ID Location Way Day DayTime NightTime StandNo
1  ABC      UP  Mon 6.00     18.00    6

我需要检查位置和方式并将它们转换为大写 - ABC,UP 一天必须是星期一 - 星期一 我需要对整个 CSV 执行此操作。我需要更正值并将所有字段写入 CSV 或编辑当前单元格并保存 CSV 我的脚本如下

file = "Myfile.csv"
while IFS="," read line
do
output=`echo $line | cut -d "," -f2`
echo $output
for i in $output
do
if [ -z $(echo $I | sed -e "s/[a-z]//g") ]
then 
echo $I | tr "[:lower:]" "[:upper:]" >> ".tempfile.CSV"
fi
done
done <$file

`1.目前,这仅写入校正值,而不是整行连同校正值。 [不确定如何循环遍历每行中的单元格值,更正需要更正的值,然后复制整行]

任何帮助都会很有用。

【问题讨论】:

标签: linux bash shell csv


【解决方案1】:

Why is using a shell loop to process text considered bad practice?

由于问题标记为linux,假设GNU sed 可用。而且输入实际上是csv,而不是空格/制表符分隔

$ cat ip.csv 
ID,Location,Way,Day,DayTime,NightTime,StandNo
1,abc,Up,mon,6.00,18.00,6
2,xyz,down,TUE,2.32,5.23,4

$ sed '2,$ {s/[^,]*/\L\u&/4; s/[^,]*/\U&/3; s/[^,]*/\U&/2}' ip.csv 
ID,Location,Way,Day,DayTime,NightTime,StandNo
1,ABC,UP,Mon,6.00,18.00,6
2,XYZ,DOWN,Tue,2.32,5.23,4
  • 2,$ 处理从第二行到文件末尾的输入
  • s/[^,]*/\L\u&amp;/4 仅将第 4 个字段的第一个字母大写
  • s/[^,]*/\U&amp;/3 将第三个字段中的所有字母大写
  • s/[^,]*/\U&amp;/2 将第二个字段中的所有字母大写

如果字段本身可以在双引号内包含, 等,请使用perlpython 等,其中包含csv 模块

【讨论】:

  • 嗨 Sundeep,它在 Gedit 上工作 :)。谢谢。问题出在 MobaXterm 编辑器上。我能知道\L\u如何表示单词中的第一个字母大写吗?
  • \L 将小写所有字母.... \u 将只大写一个字母...如果您的输入只有montue 等单词,您可以跳过使用\L
  • 谢谢,我还有一个疑问。如果你想让我打开另一个线程,我会这样做。我有时会遇到这种情况,在 100, West Bengal, Up, Thu, , , ,. 101, , , 周五, 6.00, 8.00, P3。我有这个表达式 s/,[[:blank:]]*,/,,/。这工作正常。但是当分隔符之间存在超过 1 个空格时,它不起作用
  • 对于 ex 100, West Bengal, , , , , 产生 100, West Bengal,, , , - 最后两个分隔符之间存在空格。 [注意需要在 West Bengal 等单词之间保留空格]
  • 不确定您的疑问..您是否要删除空白字段中的所有空白?如果是这样,您将需要类似echo '100, West Bengal, , , , ,' | sed ':a s/,[[:blank:]]\+,/,,/; ta'
【解决方案2】:

回想一下,在 bash 中,您有一个 参数扩展,它会将变量中的所有字符(例如 $line)转换为 大写。扩展的形式是${line^^}(注意'^^')。要读取第一个之后的所有字符并将其转换为大写,您可以执行以下操作:

declare -i c=0
while read -r line; do 
    if [ "$c" -gt '0' ]; then 
        echo "${line^^}"          ## output line converted to upper
    else
        echo "$line"
    fi
    ((c++))
done < file.txt

示例输出

$ declare -i c=0; while read -r line; do if [ "$c" -gt '0' ]; then \ 
echo "${line^^}"; else echo "$line"; fi; ((c++)); done < file.txt
ID Location Way Day DayTime NightTime StandNo
1  ABC      UP  MON 6.00     18.00    6

【讨论】:

    【解决方案3】:

    我假设您在输入中有一个无标题的 CSV 文件:

    $ cat file.csv 
    1,abc,Up,mon,6.00,18.00,6
    

    我还假设您希望输出 CSV 文件。

    如果所有这些假设都是正确的,那么:

    $ awk -F, -v OFS=, '{$2=toupper($2); $4=toupper(substr($4,1,1)) substr($4,2); print}' file.csv
    1,ABC,Up,Mon,6.00,18.00,6
    

    编辑。 如果你想保留你的标题行...

    awk -F, -v OFS=, '{if(NR>1){$2=toupper($2); $4=toupper(substr($4,1,1)) substr($4,2)} print}' file.csv
    ID,Location,Way,Day,DayTime,NightTime,StandNo
    1,ABC,Up,Mon,6.00,18.00,6
    

    【讨论】:

    • 需要复制标题。我能知道这条线需要插入的确切位置吗?目前它给我一个错误说“多调用二进制”用法:awk [options] [awk_program] [file] ... -v var=val set variable
    • @MeghnaSathyanarayan:不明白插入是什么意思。上面的命令行必须执行(不插入)。
    • 道歉 Mauro,我重新提出了我的问题。我确实执行了命令并发现了错误。我认为它可能应该添加到现有脚本的某个地方。我对 bash 很陌生,因此我可能已经搞砸了。
    猜你喜欢
    • 1970-01-01
    • 2012-10-16
    • 1970-01-01
    • 1970-01-01
    • 2012-01-18
    • 1970-01-01
    • 1970-01-01
    • 2021-01-03
    • 1970-01-01
    相关资源
    最近更新 更多