我一直在编写一个脚本来将多个 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
Run Code Online (Sandbox Code Playgroud)
对于我当前的测试,我有 25 个类似的文件,第一列中的数字不同。
我试图让这个脚本执行以下操作:
但是,我需要所有项目都在文本行 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
Run Code Online (Sandbox Code Playgroud)
我当前的脚本找到了正确的信息(项目名称、项目数据),如果我只是“回显”这些变量,它会将正确的数据打印到文件中。但是,使用 echo 它只在每个项目的长列表中打印。我希望它“跳回”到第 1 行并在当前行的末尾打印新项目,然后运行循环以在下一行的末尾打印数据。
我想这应该可以用 sed 或 awk。sed 应该有一种将文本插入到特定行的方法
sed '{n}s/search/replace/'
Run Code Online (Sandbox Code Playgroud)
其中 {n} 是要插入的行
awk 应该能够用类似的东西做同样的事情
awk -v l2="$textline" -v d="$projectdata" 'NR == l2 {print d} {print}' >> $csv_outputfile
Run Code Online (Sandbox Code Playgroud)
但是,在将脚本中的 sed 命令替换为
echo $projectname
echo $projectdata
Run Code Online (Sandbox Code Playgroud)
吐出正确的信息(所以我知道我的变量被正确填充)sed 和 awk 命令倾向于吐出它们当前 inputcsv 的全部内容;不仅仅是我想让他们做的那条线。
写入文件的每个变体的 Pastebin 输出
如您所见,sed 输出倾向于粘贴 inputcsv 的全部内容,从而使循环在一次迭代后停止。(因为它在一个循环后找到了其他项目)
所以我的问题是其中之一;
任何帮助将不胜感激。
完成这种转置的一种方法是将数据保存到关联数组中。
在下面的示例中,我们使用二维数组来跟踪数据。因为排序似乎很重要,所以我们创建一个 col 数组,并在看到新项目名称时创建一个新的增量——这个 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
}
}
Run Code Online (Sandbox Code Playgroud)
作为奖励,这里有一个脚本可以重现您的一个 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]
}
Run Code Online (Sandbox Code Playgroud)