Объединить csv-файлы с тем же именем из подкаталогов
Я нашел несколько сценариев, объединяющих текстовые файлы из разных подкаталогов, но все они создавали выходные файлы, такие как "output.txt", но не сохраняли оригинальное имя файла.
Состав
Folder_A
a.csv
b.csv
...
Folder_B
a.csv
b.csv
...
Я хотел бы получить новый a.csv, объединенный из a.csv в Folder_A и a.csv в Folder_B и т. Д., Записанный либо в родительский каталог, либо в новый выходной каталог.
В моем случае количество файлов в подкаталогах одинаковое. Там может быть более двух подкаталогов.
Полученные CSV-файлы должны содержать только одну строку заголовка.
Я знаю, что мне нужно пройтись по каталогам, но я не знаю, как создать список имен файлов и искать их, и как все это вложить.
Любая помощь приветствуется.
2 ответа
Вы можете попробовать этот скрипт bash. Он находит файлы с именем ".csv" в первом каталоге и объединяет его с тем же именем файла, что и во втором каталоге, после удаления (1d) своей первой строки (заголовок csv). Полученный файл находится в 3-м каталоге.
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
Проще, если вы делаете это более Unix-у, более гибко - требуется всего 2 команды:
- получить список имен файлов (= различное объединение файлов всех директорий)
- cat файл (ы) всех dirs в весь файл (ы) Output dir
#### 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