Объединение файлов с одинаковым заголовком в разных каталогах

#bash #find #sh

#bash #Найти #sh

Вопрос:

У меня есть эта структура папок с более чем 300 папками с разными именами, но все с одинаковым именем файла csv:

 some folder name > file_name.csv
some other folder name > file_name.csv
...
another folder name > file_name.csv
 

Все файлы имеют строку заголовка, и я пытаюсь объединить все файлы в один файл только с одним заголовком.

Просмотрел вопросы с аналогичной проблемой и дошел до этого момента, но это не работает и все равно будет выводить заголовок несколько раз в конечном выходном файле. Когда у меня есть все файлы в одном каталоге с разными именами, тогда awk 'NR == 1 || FNR > 1' *.csv >> $OUTPUT_LOCATION ; работает. Может кто-нибудь объяснить, почему это не работает, когда мои файлы находятся в разных каталогах, и предложить альтернативу?

 rm -f $OUTPUT_LOCATION

find . -name 'file_name.csv' 
  -exec awk 'NR == 1 || FNR > 1' {} >> $OUTPUT_LOCATION ;
 

Комментарии:

1. Значит, все файлы имеют одинаковый формат? Можете ли вы опубликовать пример формата?

2. Да, все в том же формате, с одинаковыми заголовками. Стандартные файлы CSV.

3. @oguzismail это работает! (на тестовом наборе данных) Можете ли вы объяснить, почему? И когда будет слишком много файлов? У меня есть 340 папок для перебора и около 31 ГБ данных для объединения в общей сложности.

4. Если вы -exec поставите точку с запятой, программа будет выполнена один раз для каждого выбранного файла. Но со знаком плюс программа запускается один раз на каждые пару тысяч файлов. Количество может меняться, но всегда конечно

Ответ №1:

В настоящее время вы выполняете команду awk для каждого файла, найденного командой find . Чтобы сохранить логику NR и FNR в существующей команде. Перенаправить результаты поиска обратно в awk для обработки нескольких файлов и так:

 awk 'NR == 1 || FNR > 1' $(find . -name 'file_name.csv') >> $OUTPUT_LOCATION
 

Ответ №2:

csvstack для этого создан пакет утилит из удобного csvkit:

 csvstack **/file_name.csv > joined.csv
 

Ответ №3:

Изменение ; на поможет, если их не слишком много file_name.csv . Но вот отказоустойчивый подход на всякий случай:

 rm output.csv
find . -name 'file_name.csv' -exec sh -c '
if ! test -f output.csv; then
  cp "$1" output.csv
  shift
fi
tail -q -n  2 "$@" >>output.csv' sh {}  
 

Экспортируйте OUTPUT_LOCATION и используйте его вместо output.csv , если необходимо.