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

Bash 使用sed/awk将变量的内容打印到输出文件中的指定行,bash,csv,awk,sed,Bash,Csv,Awk,Sed,我一直在编写一个脚本,将多个csv文件连接成一个大型csv文件。csv包含文件夹名称及其各自的大小,设置为两列,格式为“大小,项目名称” 单个csv文件的示例: 49747851728,ODIN 32872934580,_WORK 9721820722,LIBRARY 4855839655,BASELIGHT 1035732096,ARCHIVE 907756578,USERS 123685100,ENV 3682821,SHOTGUN 1879186,SALT 361558,SOFTWARE

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

单个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上,用逗号分隔,这样我就可以使用这个outputfile作为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
其中{n}是要插入的行

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

awk -v l2="$textline" -v d="$projectdata" 'NR == l2 {print d} {print}' >> $csv_outputfile
但是,在将脚本中的sed命令替换为

echo $projectname 
echo $projectdata 
吐出正确的信息(因此我知道我的变量填写正确)sed和awk命令倾向于吐出其当前inputcv的全部内容;不仅仅是我想让他们这么做

每个写入文件变量的Pastebin输出

  • -sed输出
  • -回波,普通输出(单列)
  • -echo,每个变量的详细输出
  • -期望输出
如您所见,sed输出倾向于粘贴inputcsv的全部内容,使循环在一次迭代后停止。(因为它在一个循环后找到其他项目)

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

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

非常感谢您的帮助。

完成此转换的一种方法是将数据保存到关联数组中

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

#! /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
    }
}
#/usr/bin/awk-f
开始{
FS=“,”
OFS=“,”
行数=0
cols=0
head=“”
拆分(“,数据)
拆分(“,行)
拆分(“,列)
}
!(2加元){新项目
如果(头==“”)
总人数=$2
其他的
人头=人头2美元
i=列[$2]=列++
行[i]=0
}
{
i=列[$2]
j=第[i]行++
数据[i,j]=1美元
如果(j>行)
行=j
}
结束{
打印头

对于(j=0;j用项目名称填充阵列,用值填充阵列,然后用bash printf打印,您可以在printf命令中选择列宽(当前为13个字符-%13s)

!/bin/bash
声明-i索引=0
声明-i pindex=0
在阅读项目时;做
parray[$pindex]=$project
索引=0
边读边做
数组[$pindex,$index]=“$REPLY”
指数+=1

完成如果您同意按名称对输出进行排序,则这一行可能有用:

awk 'BEGIN {FS=",";OFS=","} {print $2,$1}' * | sort | uniq
文件必须位于同一目录中。如果不是,文件列表将替换*。首先它将交换两个字段。Awk将获取文件列表并进行连接。然后对行进行排序并仅打印唯一的行。这取决于项目大小始终相同

上面简单的一行代码为每个项目提供了一行代码。如果您真的想在awk中完成所有工作并使用awk写入这两行代码,则需要执行以下操作。末尾有第二个awk,它将数组中的每个列条目累加起来,然后在末尾将其吐出:

awk 'BEGIN {FS=","} {print $2,$1}' *| sort |uniq | awk 'BEGIN {n=0}
{p[n]=$1;s[n++]=$2}
END {for (i=0;i<n;i++) printf "%s,",p[i];print "";
for (i=0;i<n;i++) printf "%s,",s[i];print ""}'

这是一个X-Y问题。您正在尝试解决因选择解决方案而导致的问题。我仍然不清楚除了连接文件外,您正在尝试执行什么操作?项目是否包含多个文件?如果是,您是否将大小相加?或者,选择第一个?给定输入文件的预期输出是什么?无论你想做什么,用一个小的awk脚本来解决都是非常琐碎的事情,但我们无法告诉你想做什么,因为你没有提供清晰、简洁、可测试的样本输入和预期输出。只要这样做,你就会得到答案。我真的不知道我的请求不清楚。样本输入在t附近给出我的帖子的op。我有很多csv文件,其中有一个包含FolderSize的列表,格式为“size,foldername”。我希望这些文件夹以列的形式显示,大小在下面,文件夹中的每个.csv文件对应一行。所需输出:我也会将该粘贴库添加到我的原始帖子中。你在“关联数组”中看到了它。
#!/bin/bash
declare -i index=0
declare -i pindex=0
while read project; do
  parray[$pindex]=$project
  index=0
  while read;do
    array[$pindex,$index]="$REPLY"
    index+=1
  done <<< $(grep -h "$project" *.csv|cut -d, -f1)
  pindex+=1
done <<< $(cat *.csv|cut -d, -f 2|sort -u)
maxi=$index
maxp=$pindex

for (( pindex=0; $pindex < $maxp ; pindex+=1 ));do
 STR="%13s $STR"
 VAL="$VAL ${parray[$pindex]}"
done
printf "$STR\n" $VAL
for (( index=0; $index < $maxi;index+=1 ));do
  STR=""; VAL=""
  for (( pindex=0; $pindex < $maxp;pindex+=1 )); do
    STR="%13s $STR"
    VAL="$VAL ${array[$pindex,$index]}"
  done
  printf "$STR\n" $VAL
done
awk 'BEGIN {FS=",";OFS=","} {print $2,$1}' * | sort | uniq
awk 'BEGIN {FS=","} {print $2,$1}' *| sort |uniq | awk 'BEGIN {n=0}
{p[n]=$1;s[n++]=$2}
END {for (i=0;i<n;i++) printf "%s,",p[i];print "";
for (i=0;i<n;i++) printf "%s,",s[i];print ""}'
awk 'BEGIN {FS=","} {print $2,$1}' *| sort |uniq | rs -C',' -T