Bash 使用sed/awk将变量的内容打印到输出文件中的指定行
我一直在编写一个脚本,将多个csv文件连接成一个大型csv文件。csv包含文件夹名称及其各自的大小,设置为两列,格式为“大小,项目名称” 单个csv文件的示例: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
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
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/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