bash - 使用 sed/awk 将变量的内容打印到输出文件中的特定行

标签 bash csv awk sed

我一直在研究将多个 csv 文件连接成一个大的 csv 的脚本。 csv 包含文件夹的名称及其各自的大小,采用 2 列设置,格式为“大小,项目名称”

单个 csv 文件的示例:

49747851728,ODIN
32872934580,_WORK
9721820722,LIBRARY
4855839655,BASELIGHT
1035732096,ARCHIVE
907756578,USERS
123685100,ENV
3682821,SHOTGUN
1879186,SALT
361558,SOFTWARE
486,VFX
128,DNA

对于我当前的测试,我有 25 个相似的文件,第一列中的数字不同。

我正在尝试让这个脚本执行以下操作:

  • 读取每个csv文件
  • 对于它看到的每个项目,如果该项目已经打印到文件中,则扫描输出文件。如果不是,打印项目名称
  • 对于每个文件,对于每个项目,如果找到该项目,则将大小打印到输出 csv。

但是,我需要所有项目都在文本行 1 上,以逗号分隔,这样我就可以将此输出文件用作 javascript 图形的输入。尺寸应添加到其项目名称下方的列中。

我当前的脚本:

csv_folder=$(echo "$1" | sed 's/^[ \t]*//;s/\/[ \t]*$//')
csv_allfiles="$csv_folder/*.csv"
csv_outputfile=$csv_folder.csv
echo -n "" > $csv_outputfile

for csv_inputfile in $csv_allfiles; do
  while read line && [[ $line != "" ]]; do
    projectname=$(echo $line | sed 's/^\([^,]*\),//')
    projectfound1=$(cat $csv_outputfile | grep -w $projectname)
if [[ ! $projectfound1 ]]; then
  textline=1
  sed "${textline}s/$/${projectname}, /" >> $csv_outputfile
    for csv_foundfile in $csv_allfiles; do
    textline=$(echo $textline + 1 | bc )
    projectfound2=$(cat $csv_foundfile | grep -w $projectname)
    projectdata=$(echo $projectfound2 | sed 's/\,.*$//')
        if [[ $projectfound2 ]]; then
          sed "${textline}s/$/$projectdata, /" >> $csv_outputfile
        fi
      done
    fi
  done < $csv_inputfile
done

我当前的脚本找到了正确的信息(项目名称、项目数据),如果我只是“回显”这些变量,它会将正确的数据打印到文件中。但是,对于 echo,它只会在每个项目中打印一个长列表。我希望它“跳回”到第 1 行并在当前行的末尾打印新项目,然后运行循环以在下一行的末尾打印数据。

我认为这应该可以通过 sed 或 awk 实现。 sed 应该有办法用

将文本插入特定行
sed '{n}s/search/replace/'

其中 {n} 是要插入的行

awk 应该能够用类似的东西做同样的事情

awk -v l2="$textline" -v d="$projectdata" 'NR == l2 {print d} {print}' >> $csv_outputfile

但是,将脚本中的 sed 命令替换为

echo $projectname 
echo $projectdata 

吐出正确的信息(所以我知道我的变量被正确填充)sed 和 awk 命令倾向于吐出它们当前 inputcsv 的全部内容;不仅仅是我希望他们使用的那一行。

Pastebin 输出每种写入文件的变体

如您所见,sed 输出倾向于粘贴 inputcsv 的全部内容,使循环在一次迭代后停止。 (因为它在一个循环后找到了其他项目)

所以我的问题是其中之一;

  • 如何让 sed/awk 以我想要的方式运行;即仅将我的 var 中的信息打印到当前文本行,而不是整个输入 csv。 sed 是否能够做到这一点,只打印一行变量?或者
  • 我是否应该通过“echo”将变量输出到一个临时文件中,然后遍历该临时文件以使 sed 按我希望的方式对行进行排序? (请记住,将来会添加更多 .csv 文件,我不能让它循环 x 次来对信息进行排序)
  • 有没有办法在不使用 sed 或 awk 的情况下将文本回显/打印到特定文本行?我缺少 printf 选项吗?其他想法?

非常感谢任何帮助。

最佳答案

完成这种转置的一种方法是将数据保存到关联数组。

在下面的示例中,我们使用二维数组来跟踪我们的数据。因为排序似乎很重要,所以我们创建了一个 col 数组,每当我们看到一个新的 projectname 时就创建一个新的增量——这个 col 数组最终成为我们数据的第一个索引。我们还创建了一个行数组,只要我们看到当前列的新数据,我们就会递增该数组。行号是我们对数据的第二个索引。最后,我们打印出所有的记录。

#! /usr/bin/awk -f
BEGIN {
    FS  = ","
    OFS = ", "
    rows=0
    cols=0
    head=""
    split("", data)
    split("", row)
    split("", col)
}
!($2 in col) { # new project
    if (head == "")
        head = $2
    else
        head = head OFS $2
    i = col[$2] = cols++
    row[i] = 0
}
{
    i = col[$2]
    j = row[i]++
    data[i,j] = $1
    if (j > rows)
        rows = j
}
END {
    print head
    for (j=0; j<=rows; ++j) {
        if ((0,j) in data)
            x = data[0,j]
        else
            x = ""
        for (i=1; i<cols; ++i) {
            if ((i,j) in data)
                x = x OFS data[i,j]
            else
                x = x OFS
        }
        print x
    }
}

作为奖励,这里有一个脚本可以从您的一个 pastebin 中重现详细的输出。

#! /usr/bin/awk -f
BEGIN {
    FS = ","
    split("", data) # accumulated data for a project
    split("", line) # keep track of textline for data
    split("", idx)  # index into above to maintain input order
    sz = 0
}
$2 in idx { # have seen this projectname
    i = idx[$2]
    x =   ORS "textline = " ++line[i]
    x = x ORS "textdata = " $1
    data[i] = data[i] x
    next
}
{ # new projectname
    i = sz++
    idx[$2] = i
    x =       "textline = 1"
    x = x ORS "projectname = " $2
    x = x ORS "textline = 2"
    x = x ORS "projectdata = " $1
    data[i] = x
    line[i] = 2
}
END {
    for (i=0; i<sz; ++i)
        print data[i]
} 

关于bash - 使用 sed/awk 将变量的内容打印到输出文件中的特定行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49388976/

相关文章:

bash - 在 Bash 中更改 "No such file or directory"消息

MySQL加载忽略一些记录

java - 我的 Java 程序没有遍历我的整个 CSV 文件

bash - awk 长度计数+1

awk 部分匹配不被打印

用于检查字符串是否在文件中的 Ruby 脚本?

php - 从 TTY 到 PHP 的 AWK 管道输出

linux - 控制寻呼机是否被任何程序使用的标准方法是什么(能够不使用寻呼机)?

bash - 如何在不同行的多个模式匹配后替换第 n 行的单词?

java - 在 Java 中将 csv 转换为 xls 时出现问题?只需要核心 Java 经验 - 问题与导入无关