Как извлечь строки и сохранить как текстовый файл в Linux

#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. Да, это правда. Спасибо!