Разделите большой файл на блоки, не разделяя запись

Я верю uid и gid параметры в файле конфигурации сервера для разделения полномочия.

auth users параметр в Вашей конфигурации явно отклоняет все другие имена пользователей, чем"backuppc".

Так, Вам нужен "backuppc" в rsyncd.secrets на "Host1", а также на командной строке на "Host2".

Попытайтесь удалить auth users оператор от /etc/rsyncd.conf, или перепроверка, что Вы - действительно пользователь backuppc на Host2 (не "пользователь" или "имя пользователя", как в примере "От host2":).

При поиске и устранении неисправностей также попытайтесь добавить strict modes = false к Вашему rsyncd файлу конфигурации.

8
21.06.2014, 12:58
7 ответов

Вот решение, которое может сработать:

seq 1 $(((lines=$(wc -l </tmp/file))/16+1)) $lines |
sed 'N;s|\(.*\)\(\n\)\(.*\)|\1d;\1,\3w /tmp/uptoline\3\2\3|;P;$d;D' |
sed -ne :nl -ne '/\n$/!{N;bnl}' -nf - /tmp/file

Оно работает, позволяя первому sed написать сценарий второго sed. Второй sed первый собирает все входные строки до тех пор, пока не встретит пустую строку. Затем он записывает все выходные строки в файл. Первый sed записывает скрипт для второго, указывая ему, куда записывать выходные данные. В моем тестовом случае этот скрипт выглядел следующим образом:

1d;1,377w /tmp/uptoline377
377d;377,753w /tmp/uptoline753
753d;753,1129w /tmp/uptoline1129
1129d;1129,1505w /tmp/uptoline1505
1505d;1505,1881w /tmp/uptoline1881
1881d;1881,2257w /tmp/uptoline2257
2257d;2257,2633w /tmp/uptoline2633
2633d;2633,3009w /tmp/uptoline3009
3009d;3009,3385w /tmp/uptoline3385
3385d;3385,3761w /tmp/uptoline3761
3761d;3761,4137w /tmp/uptoline4137
4137d;4137,4513w /tmp/uptoline4513
4513d;4513,4889w /tmp/uptoline4889
4889d;4889,5265w /tmp/uptoline5265
5265d;5265,5641w /tmp/uptoline5641

Я тестировал его следующим образом:

printf '%s\nand\nmore\nlines\nhere\n\n' $(seq 1000) >/tmp/file

Это дало мне файл в 6000 строк, который выглядел следующим образом:

<iteration#>
and
more
lines
here
#blank

...повторялся 1000 раз.

После выполнения скрипта выше:

set -- /tmp/uptoline*
echo $# total splitfiles
for splitfile do
    echo $splitfile
    wc -l <$splitfile
    tail -n6 $splitfile
done    

OUTPUT

15 total splitfiles
/tmp/uptoline1129
378
188
and
more
lines
here

/tmp/uptoline1505
372
250
and
more
lines
here

/tmp/uptoline1881
378
313
and
more
lines
here

/tmp/uptoline2257
378
376
and
more
lines
here

/tmp/uptoline2633
372
438
and
more
lines
here

/tmp/uptoline3009
378
501
and
more
lines
here

/tmp/uptoline3385
378
564
and
more
lines
here

/tmp/uptoline3761
372
626
and
more
lines
here

/tmp/uptoline377
372
62
and
more
lines
here

/tmp/uptoline4137
378
689
and
more
lines
here

/tmp/uptoline4513
378
752
and
more
lines
here

/tmp/uptoline4889
372
814
and
more
lines
here

/tmp/uptoline5265
378
877
and
more
lines
here

/tmp/uptoline5641
378
940
and
more
lines
here

/tmp/uptoline753
378
125
and
more
lines
here
2
27.01.2020, 20:12

Используя предложение csplit:

Разделение на основе номеров строк

$ csplit file.txt <num lines> "{repetitions}"

Пример

Скажем, у меня есть файл с 1000 строк в нем.

$ seq 1000 > file.txt

$ csplit file.txt 100 "{8}"
288
400
400
400
400
400
400
400
400
405

приводит к тому, что файлы выглядят так:

$ wc -l xx*
  99 xx00
 100 xx01
 100 xx02
 100 xx03
 100 xx04
 100 xx05
 100 xx06
 100 xx07
 100 xx08
 101 xx09
   1 xx10
1001 total

Вы можете обойти статическое ограничение на указание количества повторений, предварительно вычислив числа, основанные на количестве строк в вашем конкретном файле.

$ lines=100
$ echo $lines 
100

$ rep=$(( ($(wc -l file.txt | cut -d" " -f1) / $lines) -2 ))
$ echo $rep
8

$ csplit file.txt 100 "{$rep}"
288
400
400
400
400
400
400
400
400
405

Разделение на основе пустых строк

Если же Вы хотите просто разбить файл на пустые строки, содержащиеся в файле, Вы можете использовать эту версию split:

$ csplit file2.txt '/^$/' "{*}"

Пример

Скажем, я добавил 4 пустые строки в file.txt выше, и создал файл file2.txt. Вы видите, что они были добавлены вручную так:

$ grep -A1 -B1 "^$" file2.txt
20

21
--
72

73
--
112

113
--
178

179

Выше видно, что я добавил их между соответствующими номерами в моем файле-примере. Теперь, когда я запускаю команду csplit:

$ csplit file2.txt '/^$/' "{*}"
51
157
134
265
3290

Вы видите, что теперь у меня есть 4 файла, которые были разбиты на пустую строку:

$ grep -A1 -B1 '^$' xx0*
xx01:
xx01-21
--
xx02:
xx02-73
--
xx03:
xx03-113
--
xx04:
xx04-179

References

3
27.01.2020, 20:12

Если вас не волнуют приказы записей, вы можете это сделать:

gawk -vRS= '{printf "%s", $0 RT > "file.out." (NR-1)%15}' file.in

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

gawk -vRS= -v "n=$(gawk -vRS= 'END {print NR}' file.in)" '
  {printf "%s", $0 RT > "file.out." int((NR-1)*15/n)}' file.in
3
27.01.2020, 20:12

Попробуйте awk

awk 'BEGIN{RS="\n\n"}{print $0 > FILENAME"."FNR}' big_db.msg
0
27.01.2020, 20:12

Если вы ищете сплит только в конце строки, то это можно сделать с помощью опции -l для сплита.

Если вы хотите разделить строку на пустую ( \n\n), вот как я это сделаю в ksh. Я не тестировал, и, наверное, это не идеально, но что-то в этой строке сработало бы:

filenum=0
counter=0
limit=580000

while read LINE
do
  counter=counter+1

  if (( counter >= limit ))
  then
    if [[ $LINE == "" ]]
    then
      filenum=filenum+1
      counter=0
    fi
  fi

  echo $LINE >>big_db$filenum.msg
done <big_db.msg
1
27.01.2020, 20:12

Если вам не важен порядок записей, но вам нужно получить определенное количество выходных файлов, Ответ Стефана - это то, как я бы идти. Но я чувствую, что вам может быть интересно указать размер, который не должен превышать каждый выходной файл. Это на самом деле упрощает задачу, поскольку вы можете читать свой входной файл и собирать записи, пока не достигнете этого размера, а затем запустить новый выходной файл. Если это сработает для вас, большинство языков программирования могут справиться с вашей задачей с помощью короткого сценария. Вот реализация awk:

BEGIN {
    RS = "\n\n"
    ORS = "\n\n"
    maxlen = (maxlen == 0 ? 500000 : maxlen)
    oi = 1
}

{
    reclen = length($0) + 2
    if (n + reclen > maxlen) {
        oi++
        n = 0
    }
    n += reclen
    print $0 > FILENAME"."oi
}

Поместите это в файл, скажем program.awk , и запустите его с помощью awk -v maxlen = 10000 -f program.awk big_db.msg где значение maxlen - это максимальное количество байтов, которое вы хотите в одном файле. По умолчанию будет использоваться 500 КБ.

Если вы хотите получить определенное количество файлов, возможно, самый простой способ - просто разделить размер входного файла на количество файлов, которое вы хотите, а затем добавить немного к этому числу, чтобы получить maxlen . Например, чтобы получить 15 файлов из ваших 8726593 байтов, разделите на 15, чтобы получить 581773, и добавьте несколько, так что, возможно, вы получите maxlen = 590000 или maxlen = 600000 . Если вы хотите, чтобы это повторялось, можно было бы настроить программу для этого.

0
27.01.2020, 20:12
split -n l/100 input_file prefix_name

Это разделит большой файл с именем input_fileна 100 файлов с именем prefix_nameXXбез обрезки строк.

0
18.03.2021, 06:35

Теги

Похожие вопросы