Используя терминал MacOS, можно ли взять каталог текстовых файлов и объединить их в одну электронную таблицу (в формате CSV или Numbers), поэтому:
Пример 1: вот как выглядят мои текстовые файлы перед объединением:
Пример 2: вот как мои текстовые файлы должны выглядеть в электронной таблице после объединения:
(Эти примеры являются частичным извлечением. На самом деле мне нужно объединить сотни файлов).
Шаги, которые я пробовал:
Я искал ответ в Stack Overflow, но все остальные вопросы по этой задаче используют Python или Panda. Я бы предпочел решение, которое можно было бы сделать непосредственно из терминала MacOS без необходимости установки таких пакетов, как Python или Panda.
Из исследований я считаю, что можно использовать команду paste
:
paste -d '\t' *.txt > ^0-merged.csv
Однако, когда я пытаюсь это сделать, появляется следующее сообщение об ошибке: paste: Too many open files
. Он также создает совершенно пустой файл CSV.
Вы можете прокручивать добавление каждого файла.
touch merged.csv
for f in *.txt; do paste -d '\t' $f merged.csv > temp; cp temp merged.csv; done; rm temp
Сначала вы должны создать файл, так как вставка не удастся, если он не сможет найти файл.
https://unix.stackexchange.com/questions/205642/объединение большого количества файлов
Добавление новой идеи для файлов с пробелами.
#!/bin/bash
touch merged.csv
# save and change IFS
OLDIFS=$IFS
IFS=$'\n'
# read all file name into an array
fileArray=($(find ./ -name "*.txt" | sort))
# restore it
IFS=$OLDIFS
# get length of an array
tLen=${#fileArray[@]}
# use for loop read all filenames
for (( i=0; i<${tLen}; i++ ));
do
paste -d '\t' "${fileArray[$i]}" merged.csv > temp;
cp temp merged.csv;
done
rm temp
Если у вас нет пробелов в именах файлов, то это должно работать for f in `ls *.txt | sort`; do paste -d '\t' $f merged.csv > temp; cp temp merged.csv; done; rm temp
Спасибо! В моих файлах действительно есть пробелы в именах файлов. Любая работа для этого? Заранее спасибо.
Я обновил его с новой идеей. Просто поместите это в скрипт и запустите.
Потенциальная проблема здесь заключается в том, что если файлы имеют разную длину, столбцы не будут заполнены, чтобы соответствовать более длинным столбцам.
@nowait Это работает, примите, что это происходит в обратном порядке имен файлов (например, от z-A). Можно ли как-то перевернуть его, чтобы он шел от AZ? Кроме того, похоже, что прописные буквы AZ и строчные буквы AZ рассматриваются как отдельные (например, имена файлов с AZ будут идти первыми, а затем имена файлов с AZ). Он также распечатывает это сообщение об ошибке, я не уверен, что это приводит к неправильному порядку: rm temp zsh: command not found: # zsh: command not found: # zsh: command not found: # zsh: command not found: # zsh: command not found: # paste: : No such file or directory
изменение fileArray=($(find ./ -name "*.txt" | sort))
на fileArray=($(find ./ -name "*.txt" | sort -r))
изменит порядок. И если вы добавите #!/bin/bash
в качестве первой строки скрипта, он сообщит ему, какую оболочку использовать.
Руби является частью MacOS.
Данный:
head -n 3 *.txt
==> GOOD THINGS IN LIFE.txt <==
Art
Fun
Hugs
==> IN THE BACKYARD.txt <==
Hose
Tree
Soil
==> KITCHEN CUPBOARD ESSENTIALS.txt <==
Tea
Rice
Milk
==> KNITTING STITCHES.txt <==
Rib
Dip
Seed
# and the rest of your lines in each case...
Ты можешь сделать:
ruby -e '
a=[]
ARGV.sort.each{|fn|
a<<[fn]+File.open(fn).read.split(/\R/)
}
a.transpose.each{|sa|
puts sa.join(",")
}
' *.txt
Отпечатки:
GOOD THINGS IN LIFE.txt,IN THE BACKYARD.txt,KITCHEN CUPBOARD ESSENTIALS.txt,KNITTING STITCHES.txt
Art,Hose,Tea,Rib
Fun,Tree,Rice,Dip
Hugs,Soil,Milk,Seed
Earth,Fence,Salt,Tile
Honor,Porch,Pesto,Linen
Space,Patio,Flour,Cable
Sport,Grass,Honey,Wicker
Intelligence,Wading Pool,Baking Powder,Knotted Boxes
Innovation,Welcome Mat,Vegetable Oil,Chinese Wave
Confidence,Back Stoop,Tomato Paste,Checkerboard
Good Deeds,Fruit Tree,Black Pepper,Herringbone
Creativity,Downspout,Baking Soda,Stockinette
Education,Birdbath,Ketchup,Garter
Kindness,Terrace,Surer,Waffle
Integrity,Planter,Sugar,Puri Ridge
Faith,Carport,Coffee,Netted
Friends,Flowerbed,Cinnamon,Elongated
Respect,Shovel,Cheese,Farrow Rib
People,Hedges,Bread,Plaited
Yourself,Rocks,Olive Oil,Clamshell
Happiness,Lawnmower,Crackers,Bamboo
Heart,Hot Tub,Pasta,English Rib
Religion,Garden,Scissors,Basket
Wisdom,Stoop,Garlic,Raspberry
Если вам нужен «правильный» CSV с полями в кавычках, который лучше работает с Excel, вы можете использовать модуль CSV, включенный в Ruby:
ruby -r csv -e '
a=[]
ARGV.sort.each{|fn|
a<<[fn]+File.open(fn).read.split(/\R/)
}
a=a.transpose
puts CSV.generate(**{headers:true, quote_empty:true, force_quotes:true}){|csv|
csv<<a[0]
a[1..].each{|row|
csv<<row
}
}
' *.txt
Отпечатки:
"GOOD THINGS IN LIFE.txt","IN THE BACKYARD.txt","KITCHEN CUPBOARD ESSENTIALS.txt","KNITTING STITCHES.txt"
"Art","Hose","Tea","Rib"
"Fun","Tree","Rice","Dip"
"Hugs","Soil","Milk","Seed"
"Earth","Fence","Salt","Tile"
"Honor","Porch","Pesto","Linen"
"Space","Patio","Flour","Cable"
"Sport","Grass","Honey","Wicker"
"Intelligence","Wading Pool","Baking Powder","Knotted Boxes"
"Innovation","Welcome Mat","Vegetable Oil","Chinese Wave"
"Confidence","Back Stoop","Tomato Paste","Checkerboard"
"Good Deeds","Fruit Tree","Black Pepper","Herringbone"
"Creativity","Downspout","Baking Soda","Stockinette"
"Education","Birdbath","Ketchup","Garter"
"Kindness","Terrace","Surer","Waffle"
"Integrity","Planter","Sugar","Puri Ridge"
"Faith","Carport","Coffee","Netted"
"Friends","Flowerbed","Cinnamon","Elongated"
"Respect","Shovel","Cheese","Farrow Rib"
"People","Hedges","Bread","Plaited"
"Yourself","Rocks","Olive Oil","Clamshell"
"Happiness","Lawnmower","Crackers","Bamboo"
"Heart","Hot Tub","Pasta","English Rib"
"Religion","Garden","Scissors","Basket"
"Wisdom","Stoop","Garlic","Raspberry"
Комментарии:
Он также помещает имя файла вверху каждого столбца. Есть ли способ опустить имя файла? Кроме того, он, кажется, обрабатывает прописные буквы AZ и строчные буквы az как отдельные (например, имена файлов с буквами AZ будут первыми а потом имена файлов через a-z) Спасибо!
Если у вас есть файлы разной длины, вы можете дополнить конец более коротких файлов, чтобы у вас все еще была правильная матрица для транспонирования:
ruby -r csv -e '
a=[]
ARGV.sort_by{|s| s.downcase}.each{|fn|
a<<File.open(fn).read.split(/\R/)
}
max_length=a.max_by{|sa| sa.length}.length
a.each.with_index{|sa,i|
if sa.length<max_length then a[i].concat [""]*(max_length-sa.length) end }
a=a.transpose
puts CSV.generate(**{headers:true, quote_empty:true, force_quotes:true}){|csv|
csv<<a[0]
a[1..].each{|row|
csv<<row
}
}
' *.txt
Спасибо! Когда я пытаюсь это сделать, в терминале появляется эта ошибка --e:6:in transpose': element size differs (36 should be 27) (IndexError) from -e:6:in
<main>' ` Есть идеи?
Это связано с тем, что ваши файлы различаются по размеру, а ваш пример имеет одинаковые размеры. Вы можете сделать их все одинаковой длины (что тривиально в Ruby), но возникает вопрос: какие строки тогда считать пустыми? Все в конце?
@dwag Спасибо, это работает! А есть ли возможность вывода в файл, а не отображения в терминале. Он также помещает имя файла вверху каждого столбца. Есть ли способ опустить имя файла? Кроме того, похоже, что прописные буквы A-Z и строчные буквы az рассматриваются как отдельные (например, сначала будут идти имена файлов с A-Z, а затем имена файлов с az). Спасибо!
Для вывода в файл просто перенаправьте вывод в zsh / Bash с помощью > output_file
сразу после *.txt
в этом случае. Другие элементы, исправленные в последней версии.
Спасибо, это работает отлично. За исключением того, есть ли какой-либо способ получить его, поэтому он размещает текстовые файлы в столбце в алфавитном порядке имен файлов (извините, я забыл указать алфавитную часть в своем вопросе. Я так привык, что все мои файлы отображаются в в алфавитном порядке в папке, которую я забыл упомянуть!)