Я хочу разбить текстовый файл в соответствии с заданным набором строк. Например. У меня есть файл
a
b
c
d
e
f
И затем у меня есть следующие наборы строк (они могут быть сохранены, однако более удобно для одного файла несколько файлов ...).
1,2
3,6
5,4
Я хочу разделить файл так, чтобы я получил 3 файла обратно, например:
файл1
a
b
файл2
c
f
файл3
e
d
Вот 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
бит должен будет быть разбит в два отдельных вызова, подобные первому сценарию.
Следующий сценарий 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)
Другой просто awk решение :)
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#
Можно использовать инструмент split
. Набор примеров может быть найден, например, здесь
Однако в Вашем случае, что-то как
split -l 2 <inputfile>
создаст ряд файлов с двумя строками, названными чем-то как xaa, xab...
Другой 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
Вот один способ сделать это в awk
awk -F, 'NR==FNR {for (i=1;i<=NF;i++) a[$i]=FNR; next;} {print $0 >> "outfile"a[FNR];}' index file
Это читает индексный файл и сохраняет его номер строки (FNR
) в массив это индексируется списком значений на строке. Затем это читает входной файл и использует его номер строки для поиска что число выходного файла записать каждую строку в.
Сценарий 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
f1
, f2
и каталог, чтобы сохранить файлы к Выполнение это с командой
python3 /path/to/outtake.py
save_to