我发现一些脚本将来自不同子目录的文本文件连接起来,但它们都生成了像“output.txt”这样的输出文件,但没有保留原始文件名。
结构
Folder_A
a.csv
b.csv
...
Folder_B
a.csv
b.csv
...
我想要收到一个新的 a.csv,它合并了 Folder_A 中的 a.csv 和 Folder_B 中的 a.csv 等等,然后写入父目录或新的输出目录。
在我的例子中,子目录中的文件数量是相似的。 可能会有两个以上的子目录。
生成的 csv 文件应该只包含一个标题行。
我知道我必须循环遍历目录,但我不知道如何创建文件名列表并搜索它们,以及如何嵌套所有这些。
任何帮助都非常感谢。
答案1
您可以尝试这个 bash 脚本。它在第一个目录中找到名为“.csv”的文件,并在删除(1d)其第一行(csv 标题)后将其与在第二个目录中找到的相同文件名连接起来。生成的文件位于第三个目录中。
a=Folder_A
b=Folder_B
c=Folder_C
mkdir -p $c
(cd $a && find . -type f -name '*.csv') |
while read file
do ( cat "$a/$file"
[ -f "$b/$file" ] && sed '1d' <"$b/$file"
) >"$c/$file"
done
此 bash 脚本在作为参数给出的目录中查找名为“.csv”的文件,并在删除(1d)其第一行(csv 标头)后将它们与稍后找到的任何同名文件连接起来。生成的文件位于 Folder_concat 目录中。
#!/bin/bash
dest=Folder_concat
mkdir -p $dest
find "$@" -name "$dest" -prune -o -name '*.csv' |
while read file
do base=$(basename "$file")
if [ -s "$dest/$base" ]
then sed '1d' <"$file"
else cat "$file"
fi >>"$dest/$base"
done
答案2
如果你做得更像 Unix,更像 shell,那就更容易了——只需要 2 个命令:
- 获取文件名列表(=所有目录文件的不同联合)
- 将所有目录的部分文件放入输出目录的整个文件中
#### get list of files as Distinct Union of all dirs' files # (alas, basename can only handle ONE filename at a time # so have to loop through them)
DISTINCTUNION_ALLFILES=`
for FILE in Folder_{A,B,C,D}/*
do
basename $FILE
done | sort | uniq
`
#
# syntax explanation:
# 1. for VARIABLE in LIST: loops b/w DO and DONE, with Variable taking each value in the list
# 2. {A,B,C} is Shell (bash) expansion: creates N words, 1 for each comma-separated sub-word
# e.g.: dir{A,B} -> dirA dirB
# e.g.: myfile.{dll,o,out} -> myfile.dll myfile.o myfile.out
# e.g.: myfile{,.tmp} -> myfile myfile.tmp
# 3. BASENAME strips away the Path leaving just the filename (cf.Dirname for the opposite)
# 4. the BACKQUOTES (``) take the command's Output and re-place it on that part of the commandline
# 5. | takes the total output and Sorts it, then | takes _that_ to Uniq which removes duplicates
# 6. the whole lot is then stored in the VariableName
#### cat all dirs' part-file(s) into Output dir's whole-file(s)
for FILE in $DISTINCTUNION_ALLFILES
do
cat Folder_{A,B,C,D}/$FILE > OutputDir/$FILE
done
#
# syntax explanation:
# 1. same For loop as before, same filename expansion as before
# 2. files which are not in ALL dirs will generate errors but won't stop the conCATenation
# 3. result goes into OutputDir, 1 file per filename