разбить файл на основе заранее определенного набора строк

Я хочу разбить текстовый файл в соответствии с заданным набором строк. Например. У меня есть файл

a
b
c
d
e
f

И затем у меня есть следующие наборы строк (они могут быть сохранены, однако более удобно для одного файла несколько файлов ...).

1,2
3,6
5,4

Я хочу разделить файл так, чтобы я получил 3 файла обратно, например:

файл1

a
b

файл2

c
f

файл3

e
d
5
задан 19 March 2015 в 19:08

7 ответов

Вот bash сценарий, предполагающий, что Ваш входной файл называют infile, и диапазоны хранятся 1-per-line в файле, названном разделениями:

i=1
for range in $(< splits); do
  sed -n "$(echo "$range" | cut -f1 -d, )p" infile > "file$i"
  sed -n "$(echo "$range" | cut -f2 -d, )p" infile >> "file$i"
  ((i++))
done

Это просто использует sed для печати строк, определенных диапазонами, и сохраняет каждый результат как новый файл (созданные файлы называют file1 file2 file3 и т.д.). Два вызова sed используются для сохранения указанного порядка строк.

Примечание, что нет никакого формата или проверки ошибок, сделанной этим простым сценарием и существующими названными файлами, например, file1, будет перезаписано.

 

<час>

А упростил альтернативу (любезность @muru) использование while read и разрешение удару разделить диапазоны вместо сокращения:

i=1
while IFS=',' read n1 n2 
do
    sed -n "$n1 p; $n2 p" infile > "file$i"
    ((i++))
done < splits

, Если порядок строк в выходных файлах важен (например, строки 5,4! = 4,5), тогда эти sed бит должен будет быть разбит в два отдельных вызова, подобные первому сценарию.

3
ответ дан 19 March 2015 в 19:08

Следующий сценарий Python сделает разделение:

#!/usr/bin/python3

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('file', type=argparse.FileType('r'))
parser.add_argument('lines', type=argparse.FileType('r'))

args = parser.parse_args()

file_lines = list(args.file)

for i, l in enumerate(args.lines):
    r = l.rstrip().split(',')
    with open('file{}'.format(i+1), 'w') as f:
        for k in r:
            try:
                f.write(file_lines[int(k)-1])
            except IndexError: # Ignore lines out of range
                pass

Просто вызов это этот путь:

./split.py file lines

, Где <file> abcdef файл и <lines> 1,2... диапазон строк (у Вас может даже быть несколько строк как 1,6,3,18,5)

2
ответ дан 19 March 2015 в 19:08

Другой просто решение :)

awk -F, 'NR==FNR{ X[NR]=$0; next } {print X[$1] RS X[$2]>"out"FNR}' file lines

Объяснение:

NR==FNR    - Execute next block for 1st file only (*file*)
X[NR]=$0   - Create an associative array with key as 'NR' (line number) and copy
             whole line ($0) into it as its content.
next       - Jump to reading the next row from *file* (1st file)

print X[$1] RS X[$2]   
           - Print those line from array X that its line-number is the same as 
             value of first field in *lines* file then print a new-line(RS) and 
             print the line that its line-number is the same as value of second 
             field in *lines* file again and redirect the result into out#
2
ответ дан 19 March 2015 в 19:08

Можно использовать инструмент split. Набор примеров может быть найден, например, здесь

Однако в Вашем случае, что-то как

split -l 2 <inputfile>

создаст ряд файлов с двумя строками, названными чем-то как xaa, xab...

0
ответ дан 19 March 2015 в 19:08

Другой bash решение, принимая input как вход, pattern как шаблон и output как вывод:

#!/bin/bash
i=0 # set the output number to 0
while read row; do # for each line in file `pattern` as $row
    columns=$(<<< $row tr ',' '\n') # store each line obtained by transforming ',' in '\n' inside $row in an array $columns
    for column in $columns; do # for each member in array $columns as $column
        sed -n "${column}p" input
    done > output$i # write column $column in `input` to `output$i`
    ((i++)) # increment the output number
done < pattern
2
ответ дан 19 March 2015 в 19:08

Вот один способ сделать это в awk

awk -F, 'NR==FNR {for (i=1;i<=NF;i++) a[$i]=FNR; next;} {print $0 >> "outfile"a[FNR];}' index file

Это читает индексный файл и сохраняет его номер строки (FNR) в массив это индексируется списком значений на строке. Затем это читает входной файл и использует его номер строки для поиска что число выходного файла записать каждую строку в.

2
ответ дан 19 March 2015 в 19:08

Сценарий Python ниже сделает задание также:

#!/usr/bin/env python3
#--- set the paths below
f1 = "/path/to/predifined_rows.txt"; f2 = "/path/to/outtakes.txt"; save_to = "directory/to/save/the/outtakes"
#---

rows = [l.strip() for l in open(f1).readlines()]
outtakes = [eval(l.strip()) for l in open(f2).readlines()]
for i in range(len(outtakes)):
    s = ("\n").join([rows[n-1] for n in outtakes[i]])
    with open(save_to+"/"+str(i+1), "wt") as out:
           out.write(s)
  • Копия это в пустой файл, сохраните его как outtake.py
  • В headsection, установите путь к f1, f2 и каталог, чтобы сохранить файлы к
  • Выполнение это с командой

    python3 /path/to/outtake.py
    

, Что это делает

  1. , это читает числа из второго файла, читая строки как список из чисел
  2. для каждой из строк, это собирает соответствующие объекты первого файла (индексом) и выписывает его, в отдельно пронумерованные файлы, в каталоге, определенном в save_to
1
ответ дан 19 March 2015 в 19:08

Другие вопросы по тегам:

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