2015-11-10 3 views
2

У меня есть большой файл в следующем формате:Плевать файл на несколько файлов

From fc2868d745defcc4deb0ebdce8fe8dac78b447ea Mon Sep 17 00:00:00 2001 
From: email address 
message content 

From 39a833c2f01030619629daa3b613e3985b2e4e7a Mon Sep 17 00:00:01 2001  
From: email address 
message content 

From 833c2f01030619629daa3b613e3985b2e4e7a427 Mon Sep 17 00:00:01 2001 
From: email address 
message content 

Я хотел бы, чтобы разбить файл на несколько файлов, так что первый файл содержит

From fc2868d745defcc4deb0ebdce8fe8dac78b447ea Mon Sep 17 00:00:00 2001 
    From: email address 
    message content 

Следующий файл содержит следующий раздел.

Ключ, который определяет следующий файл является «С [аз] [0-9]»

Таким образом, «Из космоса некоторые буквы/цифры»

содержание сообщений является несколько строк, до 1000

Любые идеи, как это сделать в bash?

Пример 3, содержащий сообщения: http://pastebin.com/xWmuzfRC

+0

Can сообщение появляется в нескольких строках или только одна линия? – anubhava

+0

Я обновил вопрос. Сообщение будет состоять из нескольких строк. Что угодно от 10 до 1000. – Greg

+1

Есть ли пустая строка перед каждой линией 'From ...', как показано? – anubhava

ответ

0

Может быть, вы можете использовать это регулярное выражение.

(From\s.*\n+From:\s+.*\n+.*\n) 

Смотрите этот пример: https://regex101.com/r/fJ2rF9/1

+0

, похоже, не работает, если содержимое сообщения несколько строк. – Greg

+0

вы можете вставить все данные в pastebin? (удалить все личные данные), но важно получить структуру данных. – wu4m4n

+0

Я добавил пастебин к OP. – Greg

2

Вы можете использовать AWK:

awk '/^From [[:alnum:]]+/{if (fn) close (fn); fn = "file" ++i ".txt"} 
      {print > fn} END{close(fn)}' file 

Это создаст выходные файлы как file1.txt, file2.txt, file3.txt.

+1

Содержимое сообщения будет содержать пустые строки, поэтому вы хотите только увеличить имя файла для записей 'From', но распечатать каждую запись до« текущего »имени файла. –

+0

Спасибо, это хороший момент, я исправил его сейчас. – anubhava

0

Следующая картина будет работать:

(^From.*\n)(From:.*\n)((?!From)[\s\S])*$ 
  • Группа 1: матч все, что beggins с From, до конца текущей строки.
  • Группа 2: сопоставьте все, что нищих From:, до конца текущей строки.
  • Группа 3: Совсем все, включая разрывы строк, кроме From.
0

Aaaghh ... Оказывается, большой файл из мерзавца и могут быть разделены с git mailsplit :)

мерзавец mailsplit Разбивает файл MBox или Maildir в список файлов: «0001» " 0002 ".. в указанном каталоге, чтобы вы могли обрабатывать их дальше оттуда.

https://git-scm.com/docs/git-mailsplit

+0

Это не дает ответа на вопрос. Чтобы критиковать или просить разъяснения у автора, оставьте комментарий ниже их сообщения. - [Из обзора] (/ review/low-quality-posts/10161037) – aschipfl

+1

@aschipfl Нет, это ** является ** ответом. –

+0

@KevinGuan, для ответа на этот вопрос я ожидал немного больше, чем просто «взять этот инструмент» ... – aschipfl

2
#script 20151110f.sh 
#input file: 20151110f.dat 
#usage bash 20151110f.sh 20151110f.dat 

inf=$1 # source file 
num=1 
while read -r line 
do 
    echo "$line" | grep -q "From [a-z0-9]" # check if a new message 
    if [ $? -eq 0 ] 
    then 
     file="file"${num}.dat 
     echo "$line" > $file 
     num=$((num + 1)) #inc so that next file name will be one higher 
    else 
     echo "$line" >> $file 
    fi 
done < "$inf" 
+0

Вы можете удалить использование grep: 'if [[$ line ==" From "[a-z0-9] *]]; then' –

+0

Кроме того, чтобы сохранить ведущие/конечные пробелы, используйте 'while IFS = read -r line' –

Смежные вопросы