在Unix Shell Script中写出时出现意外的新行

时间:2014-01-14 15:04:44

标签: linux shell unix

您好我正在尝试输出一个CSV文件,并且不断将我的字符串部分写入新行。

整个脚本读入一个CSV文件,该文件有一个时间戳,将其转换,然后将Epoch时间作为新变量附加到行尾,并输出文件。

#!/bin/bash 
OLDIFS=$IFS 
IFS=","
cat test.csv | while read Host AName Resource MName TimeStamp Integer_Value Epoch; 
do 

Epoch=$(date -d "$TimeStamp GMT" +%s)

if [ -z "$Epoch" ]
then
    (echo "$Host, $AName, $Resource, $MName, $TimeStamp, $Integer_Value, Epoch,";) >> target.csv

else
    (echo "$Host, $AName, $Resource, $MName, $TimeStamp, $Integer_Value, $Epoch,";) >> target.csv

fi

done

我试图设置一个标题,然后写出附加的变量,expect,这只发生在新值上,它将附加的变量放到一个新行。

#Host, AName, Resource, MName, Actual Start Time, Integer Value
, Epoch,
ABCD89A, Admin, shop, Stall Count, 2014-01-06 09:00:00.0, 0
, 1388998800,

而不是

#Host, AName, Resource, MName, Actual Start Time, Integer Value, Epoch,
ABCD89A, Admin, shop, Stall Count, 2014-01-06 09:00:00.0, 0, 1388998800,

当我移动订单时,它不会发生。对不起,我知道这可能很简单,我是Unix脚本的新手。

修改

我现在已将代码更改为:

#!/bin/bash 
OLDIFS=$IFS 
IFS=","
while read Host AName Resource MName TimeStamp Integer_Value Epoch
do 

Epoch=$(date -d "$TimeStamp GMT" +%s)

if [ -z "$Epoch" ]
then
    echo "$Host, $AName, $Resource, $MName, $TimeStamp, $Integer_Value, Epoch,"

else
    echo "$Host, $AName, $Resource, $MName, $TimeStamp, $Integer_Value, $Epoch,"

fi

done < test.csv  > target.csv

我仍然遇到同样的问题。

另外一个问题,如果有人知道我为什么得到:找不到命令 date:运行日期部分时的无效日期`Actual Start TimeStamp GMT',但它生成正确的日期并运行脚本。

2 个答案:

答案 0 :(得分:1)

试试这个脚本:

IFS=[,$'\r']; while read Host AName Resource MName TimeStamp Integer_Value Epoch
do
   # ignore first line with headers
   [[ "$Host" == \#* ]] && continue

   Epoch=$(date -d "$TimeStamp GMT" +%s)

   if [ -z "$Epoch" ]; then
     echo "$Host, $AName, $Resource, $MName, $TimeStamp, $Integer_Value, Epoch,"
   else
     echo "$Host, $AName, $Resource, $MName, $TimeStamp, $Integer_Value, $Epoch,"    
   fi
done < test.csv > target.csv

它有两点不同:

  1. 它将\r视为字段分隔符,并且不包括读取变量
  2. 中的字段
  3. 忽略输入CSV文件标题的第一行

答案 1 :(得分:0)

我个人会在这里使用awk是这样的:

awk  -F"," '{timestamp=$5;  gsub(":"," ",timestamp); gsub("-"," ",timestamp);   EPOCH=(mktime(timestamp)*1000)} {print $0","EPOCH}' 1.csv 

产地:

ABCD89A, Admin, shop, Stall Count, 2014-01-06 09:00:00, 0,1388998800000

1个衬里,可以满足您的所有需求:

只要你的时间戳是那种确切的格式,那么awk中的gsum就是remvoving:并且 - 从日期格式传递到mktime以产生时间戳,以秒为单位,最后完全打印每行$ 0“,”EPOCH哪个现在转换时间值

 awk  -F"," '{ 
     timestamp=$5;  
     gsub(":"," ",timestamp); 
     gsub("-"," ",timestamp);   
     EPOCH=(mktime(timestamp)*1000)
     } 
     {
      print $0","EPOCH
      }' your_File.csv 

在此扩展。

现在扩展这个以便你读取这个文件通过awk解析它然后将输出泵回到同样的文件中你可以这样:

cp 2.csv 1.csv
cat 1.csv 
ABCD89A, Admin, shop, Stall Count, 2014-01-06 09:00:00, 0
ABCD89N, Admin, shop, Stall Count, 2014-01-06 09:00:00, 0
file="1.csv"; output=$(awk  -F"," '{ timestamp=$5;gsub(":"," ",timestamp);gsub("-"," ",timestamp);EPOCH=(mktime(timestamp));}{print $0", "EPOCH;}' $file 2>&1);  echo "$output" > $file
cat 1.csv 
ABCD89A, Admi , shop, Stall Cou t, 2014-01-06 09:00:00, 0, 1388998800
ABCD89N, Admi , shop, Stall Cou t, 2014-01-06 09:00:00, 0, 1388998800

现在要扩展此方法,以确保您不会覆盖已经设置的相同文件,并以秒为单位运行这样的时间:

cp 2.csv 1.csv
 cat $file
ABCD89A, Admin, shop, Stall Count, 2014-01-06 09:00:00, 0
ABCD89N, Admin, shop, Stall Count, 2014-01-06 09:00:00, 0
 file="1.csv"; output=$(awk  -F"," '{ if (NF==7) { print "ERROR"; next; }else{timestamp=$5;gsub(":"," ",timestamp);gsub("-"," ",timestamp);EPOCH=(mktime(timestamp));}{print $0", "EPOCH;}}' $file 2>&1); if echo "$output"|grep -q "ERROR"; then  echo "$output"; else echo "$output" > $file; fi
 file="1.csv"; output=$(awk  -F"," '{ if (NF==7) { print "ERROR"; next; }else{timestamp=$5;gsub(":"," ",timestamp);gsub("-"," ",timestamp);EPOCH=(mktime(timestamp));}{print $0", "EPOCH;}}' $file 2>&1); if echo "$output"|grep -q "ERROR"; then  echo "$output"; else echo "$output" > $file; fi
ERROR
ERROR
 cat $file
ABCD89A, Admin, shop, Stall Count, 2014-01-06 09:00:00, 0, 1388998800
ABCD89N, Admin, shop, Stall Count, 2014-01-06 09:00:00, 0, 1388998800

您将在第二次运行时注意到它输出ERROR并且实际上并没有覆盖相同的文件......

通过这种方式,您可以自动执行某些脚本并执行此操作并感到安全,因为它不会向现有csv添加额外的内容

或者将临时文件用于大量csv文件: 这是一个毫无意义的路线我只是测试我是否可以回到我发现在奇怪的场合工作的同一个文件 - 真的很棒。

(awk  -F"," '{ timestamp=$5;gsub(":"," ",timestamp);gsub("-"," ",timestamp);EPOCH=(mktime(timestamp));}{print $0", "EPOCH;}' 1.csv 2>&1|tee /tmp/a; mv /tmp/a 1.csv;)

因为这可能只是

(awk  -F"," '{ timestamp=$5;gsub(":"," ",timestamp);gsub("-"," ",timestamp);EPOCH=(mktime(timestamp));}{print $0", "EPOCH;}' 1.csv >/tmp/a; mv /tmp/a 1.csv;)

使用$ output的第一个方法将csv作为变量存储到内存中,然后将其推回到文件中。第二个或最后一个方法可能是/ tmp文件的最后一次尝试使用临时文件进行处理。我猜你选择的方法可能取决于你的CSV文件的大小。如果我们正在谈论演出并且它不是一个非常强大的机器,那么临时文件是要走的路。记忆显然更清晰,应该是最快的。

这只是我对此的意见 - 对于希望做类似事情的其他人来说它可能会派上用场。