Как я могу разделить файл, сопоставив контекст строки? - PullRequest
2 голосов
/ 04 декабря 2011

У меня есть файл, x, с разделителями разделов:

The first section

#!

The second section

#!

The third section

И я хочу разбить его на последовательность отдельных файлов, например:

The first section
#!

The second section
#!

The third section

Я думал, что csplit будет решением с командной строкой что-то вроде:

$ csplit -sk x '/#!/' {9999}

Но второй файл (xx01) в итоге содержит оба разделителя:

#!

The second section

#!

Есть какие-нибудь идеи о том, как достичь того, что я хочу, в соответствии с POSIX? (Да, я мог бы обратиться к Perl / Python / Ruby и друзьям; но дело в том, чтобы расширить свои знания оболочки.)


Я беспокоюсь, что нашел ошибку в OSX csplit. Могут ли люди попробовать и сообщить мне результаты?

#!/bin/sh

test -e

work="$(basename $0).$RANDOM"
mkdir $work

csplit -sk -f "$work/" - '/#/' '{9999}' <<EOF
First
#
Second
#
Third
EOF

if [ $(grep -c '#' $work/01) -eq 2 ]; then
  echo FAIL Repeat
else
  echo PASS Repeat
fi

rm $work/*

csplit -sk -f "$work/" - '/#/' '/#/' <<EOF
First
#
Second
#
Third
EOF

if [ $(grep -c '#' $work/01) -eq 2 ]; then
  echo FAIL Exact
else
  echo PASS Exact
fi

uname -a

Когда я запускаю его на своем ящике со снежным барсом, я получаю:

$ ./csplit-test
csplit: #: no match
FAIL Repeat
PASS Exact
Darwin lani.bigpond 11.2.0 Darwin Kernel Version 11.2.0: Tue Aug  9 20:54:00 PDT 2011; root:xnu-1699.24.8~1/RELEASE_X86_64 x86_64

И на моей коробке Debian я получаю:

$ sh ./csplit-test 
csplit: `/#/': match not found on repetition 2
PASS Repeat
PASS Exact

Ответы [ 4 ]

2 голосов
/ 04 декабря 2011

мне кажется, это работает на LINUX:

csplit -sk filename '/#!/' {*}

дает:

$ more xx00
The first section

$ more xx01
#!

The second section

$ more xx02
#!

The third section

Вы также можете использовать Ruby или Perl, чтобы сделать это в крошечном скрипте, и избавиться от разделителей вместе


в Fedora 13 Linux:

$ ./test.sh 
csplit: `/#/': match not found on repetition 2
PASS Repeat
PASS Exact
Linux localhost.localdomain 2.6.34.8-68.fc13.x86_64 #1 SMP Thu Feb 17 15:03:58 UTC 2011 x86_64 x86_64 x86_64 GNU/Linux
1 голос
/ 04 декабря 2011

Использование awk и тестирование на машине linux:

Моя версия awk :

$ awk --version | head -1
GNU Awk 4.0.0

Содержимое infile :

$ cat infile
The first section

#!

The second section

#!

The third section

Содержимое сценария awk :

$ cat script.awk
BEGIN {
        ## Set 'Input Record Separator' variable.
        RS = "#!";
}

{
        ## Set an integer variable as output file name.
        ++filenum;
}

## For first section.
FNR == 1 {
        ## Remove leading and trailing spaces.
        sub( /^\s+/, "", $0);
        sub( /\s+$/, "", $0);

        ## Print to output file.
        printf "%s\n", $0 > filenum ".txt"
}

## For sections from second one to last one.
FNR > 1 {
        ## Remove trailing spaces.
        sub( /\s+$/, "", $0);

        ## Print to output file.
        printf "%s%s\n", RS, $0 > filenum ".txt"
}

Запуск сценария:

$ awk -f script.awk infile

Проверить вывод:

$ ls [0-9].txt
1.txt  2.txt  3.txt
$ cat 1.txt 
The first section
$ cat 2.txt 
#!

The second section
$ cat 3.txt 
#!

The third section
1 голос
/ 04 декабря 2011

Хоть и не идеально, но вы можете сделать что-то подобное с awk.

Ваш файл:

[jaypal:~/Temp] cat f0
The first section

#!

The second section

#!

The third section

Получить все до #!, используя это (вы можете перенаправить это в файл)

[jaypal:~/Temp] awk '/#!/{exit;}1' f0 
The first section

Получите #! с последующим содержимым и разбейте перед следующим #!.

[jaypal:~/Temp] awk '/^#!/{x++}{print >(x".txt")}' f0
[jaypal:~/Temp] ls *.txt
1.txt 2.txt
[jaypal:~/Temp] cat 1.txt 
#!

The second section

[jaypal:~/Temp] cat 2.txt 
#!

The third section

Вы можете легко справиться с perl, используя что-то вроде этого -

#!/usr/bin/perl

undef $/;
$_ = <>;
$n = 0;

for $match (split(/(?=#!)/)) {
      open(O, '>temp' . ++$n);
      print O $match;
      close(O);
}

Файлы, созданные скриптом:

[jaypal:~/Temp] cat temp1 
The first section

[jaypal:~/Temp] cat temp2 
#!

The second section

[jaypal:~/Temp] cat temp3 
#!

The third section
1 голос
/ 04 декабря 2011

Э-э-э (Установка FreeBSD 8.1 выполняется на виртуальной машине Parallels)

src ./test_split.sh
csplit: #: no match
FAIL Repeat
PASS Exact
FreeBSD <hostname> 8.1-RELEASE FreeBSD 8.1-RELEASE #0: Mon Jul 19 02:55:53 UTC 2010 root@almeida.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC i386
...