#linux
#linux
Вопрос:
У меня есть набор данных из одного столбца и 500 строк, для которых я хотел бы извлечь каждую строку и сохранить ее как отдельный файл, так что в итоге у меня получается 500 файлов. Данные выглядят следующим образом:
100002
100003
100004
100005
100006
100007
...
и я хочу, чтобы каждое из этих чисел было в их собственном файле.
Для моего уровня кодирования я могу понять, возможно, делая что-то вроде;
awk -F, 'NR==1 {print $0}' wholefile.txt> individual1.txt
может сработать с изменением чисел вручную, но как мне настроить это, чтобы выполнять итерации по каждой строке, а также изменять создаваемый файл, чтобы у них были уникальные имена, такие как individual1, individual2 и т.д.
Например, открытие individual1.txt показал бы мне 100001, но имя файла не было бы individual10001
Ответ №1:
Если вас не волнует окончание .txt
в именах файлов, вы могли бы использовать split
команду
split -l 1 -d -a 3 wholefile.txt individual
Это создаст файлы с последовательно пронумерованным суффиксом individual000
, individual001
и т.д. Вплоть до количества строк в wholefile.txt
. Числа не зависят от содержимого wholefile.txt
.
Смотрите man split
-d use numeric suffixes starting at 0, not alphabetic -a, --suffix-length=N generate suffixes of length N (default 2) --numeric-suffixes[=FROM] same as -d, but allow setting the start value -l, --lines=NUMBER put NUMBER lines/records per output file
Аргумент option -a 3
создает числа из 3 цифр. Возможно, вам придется изменить это в зависимости от количества строк в wholefile.txt
. Начальные нули гарантируют, что файлы могут быть отсортированы в лексикографическом порядке.
Если вы хотите начинать числа с 1 вместо 0, замените -d
на --numeric-suffixes=1
.
Если вы хотите удалить начальные нули, вы можете использовать скрипт для переименования файлов после разделения. Вы также можете добавить .txt
при необходимости.
for file in individual*
do
newname="$(echo $file|sed 's/([^0]*)(0*)([0-9])/13/').txt"
mv "$file" "$newname"
done
sed
Команда выполняет поиск трех групп
[^0]*
0 или более символов, которые не0
0*
0 или более0
символов[0-9]
цифра от0
до9
и заменяет этот шаблон на 1-ю и 3-ю группы, опуская 2-ю группу. Здесь это работает, потому что префикс individual
не содержит чисел. В противном случае sed
команду пришлось бы расширить.
Комментарии:
1. Спасибо вам за это и за пояснения. Есть ли способ указать индивидуальное имя файла {number} в виде возрастающих чисел (1,2,3,4 и т.д.), Но не являющееся числом, которое фактически находится в строке исходного набора данных?
2. @DN1 Файлы будут созданы с возрастающими номерами, но с заполнением 0. Я изменил суффикс с 6 цифр на 3 цифры, чтобы показать, что он не соответствует номерам в файле.
3. самый чистый ответ!
Ответ №2:
Что-то вроде этого
count = 0
for i in `cat wholefile.txt`
do
# or let count=count 1
count=$((count 1))
echo $i >> individual$count.txt
done
Комментарии:
1. Это перезапишет файл, если в нем есть две идентичные строки.
2. Спасибо за ваш пост и комментарии, к счастью для меня, каждая строка уникальна, так что это работает. Однако для имен файлов они являются отдельными номерами вместо ‘individual1’ ‘individual2’ и т.д. Есть ли способ для меня в этом коде указать, что файл будет называться individual {номер}? Если это имеет смысл
3. @DN1 только что обновил код для того же, пожалуйста, рассмотрите возможность голосования и принятия ответа, если это решит ваши проблемы, чтобы другим было ясно, что проблема решена.
4. Спасибо вам за это. Проблема для меня в том, что я не хочу, чтобы число $ i было числом, которое находится в строке в исходном наборе данных, я просто хочу, чтобы оно было 1,2,3,4,5 и так далее (даже если число в файле будет похоже на 123439 или что-то в этом роде), возможно ли это?
5. Да, это возможно, если ваш файл содержит 1000 строк, тогда вы хотите, чтобы имена файлов были такими
individual998
и т.д.?
Ответ №3:
Вот цикл по номерам строк вместе с sed
командой, которая печатает строку. Выходные данные записываются в отдельные файлы, как и предполагалось.
for i in $(seq 1 $(wc -l wholefile.txt | grep -o '^ *[0-9] ')); do
sed -n "${i}p" wholefile.txt > invidividual${i}.txt
done
Обратите внимание, что для 500 файлов имена выходных файлов не будут правильно отформатированы. Возможно, вы захотите заменить указанное выше имя файла на invidividual$(printf "d" ${i}).txt
.
Ответ №4:
Используйте while read -r line;
для чтения файла построчно и записи в него с помощью echo
user@vmdeb ~ % cat nums.txt
100001
100002
100003
100004
100005
user@vmdeb ~ % while read -r line; do echo "$line" > "$line".txt; done < nums.txt
user@vmdeb ~ % ls
100001.txt 100002.txt 100003.txt 100004.txt 100005.txt nums.txt
user@vmdeb ~ % cat 100001.txt
100001
Ответ №5:
Чистое решение bash — это
j=0; while read -r line; do echo "$line" > "individual.$((j )).txt"; done < file
Решение awk было бы
awk '{f=sprintf("individual.%0.5d.txt",NR); "print > f; close(f) }' file
Чистое разделенное решение
split -l 1 -d -a 5 --additional-suffix ".txt" file individual.
Ответ №6:
Вы можете сделать что-то вроде этого..
count = 1
cat wholefile.txt | while read line ;
do
echo $line >> individualtextfile_$count.txt
count=$[count 1]
done
Комментарии:
1. Вам не нужно
cat
. Просто используйтеwhile read line; do ... done < wholefile.txt
. Преимущество этого заключается в том, что цикл выполняется не в подоболочке. Сделайтеecho count $count
после цикла, чтобы увидеть разницу.2. Да, это правда. Спасибо!