1

下面是一个 bash shell 脚本,用于接收 csv 文件并吐出按我想要的方式格式化的行(还有一些更改,但我只保留了影响下面显示的数组)。

FILENAME=$1
cat $FILENAME | while read LINE
do
    OIFS=$IFS;
    IFS=","
    columns=( $LINE )
    date=${columns[4]//\"/}
    columns[13]=${columns[13]//\"/}
    columns[4]=$(date -d $date +%s)
    newline=${columns[*]}
    echo $newline
    IFS=$OIFS;
done

我正在为 CentOS 6.3 使用 GNU bash v 4.1.2(1)-release。我试过把引号像

newline="${columns[*]}"

仍然没有运气。

以下是样本数据线

112110120001299169,112110119001295978,11,"121.119.163.146.1322221980963094","2012/11/01"

似乎应该将数组输出为逗号分隔的字符串。相反,字符串是用空格分隔的。有谁知道原因吗?

我怀疑这与以下事实有关:如果我在脚本中回显 $IFS 它是一个空字符串,但是当我回显 "${IFS}" 时,它就是我期望的逗号。

编辑:解决方案

我找到了解决方案。当回显 $newline 时,我必须在它周围使用引号,即

echo "$newline"

否则,它将使用默认空白。我相信它与bash有关,当你用引号强制它时,它只代替IFS。

4

2 回答 2

2

我不清楚为什么,但是当扩展 ${array[*]} 在双引号中时,bash 似乎只使用 IFS 的第一个字符作为分隔符:

$ columns=(a b "c d e" f)
$ IFS=,
$ echo ${columns[*]}
a b c d e f
$ echo "${columns[*]}"
a,b,c d e,f
$ newline=${columns[*]}; echo "$newline"
a b c d e f
$ newline="${columns[*]}"; echo "$newline"
a,b,c d e,f

幸运的是,解决方案很简单:使用双引号 ( newline="${columns[*]}")

(顺便说一句,我的测试都是在 bash v3 和 v2 上进行的,因为我手边没有 v4;所以对你来说可能会有所不同。)(更新:在 bash v4.2.10 上测试,结果相同。)

于 2012-12-22T03:03:50.383 回答
1

编辑感谢@GordonDavidson,删除了关于 IFS 如何在 bash 中工作的错误评论。

awk有一对非常好的 vars, nameFS=","; OFS="|"可以执行这种转换。您必须构造awk -F, '{"date -d "$date" +%s" | getline columns[4]}'或类似的方法来调用外部程序和填充变量。不像 shell 那样直观c[4]=$(date ...),但awk它是一个非常好的工具,可以像您在问题中概述的那样学习数据操作。

就像是

#!/bin/awk -f
{
  # columns=( $LINE )
  split($0, columns)

  # date=${columns[4]//\"/}
  myDcolucolumns[4] ; gsub(/\"/, "", myDate)
  # gcolumns[13]=${columns[13]//\"/}
  gsub(/\"/,""columns[13]}
  # columns[4]=$(date -d $date +%s)
  "date -d '"$date"' +%s" | getline columns[4]

  #Don_t_need_this newline=${columns[*]}

  #echo $newline
} print  $0

像这样使用

 cat myFile | myAwkScript 

应该达到相同的结果。

抱歉,我现在没有时间或样本数据来测试这个。随时回复您收到的错误消息,我会看看是否可以提供帮助。

您还可以考虑使用 1 行示例数据和要处理的日期值更新您的发布。IHTH

于 2012-12-22T02:42:09.737 回答