it-swarm.com.de

Teilen Sie eine Datei nach Trennzeichen in mehrere Dateien

Ich habe eine Datei mit -| als Trennzeichen nach jedem Abschnitt ... muss für jeden Abschnitt separate Dateien erstellen, die Unix verwenden.

beispiel für eine Eingabedatei

wertretr
ewretrtret
1212132323
000232
-|
ereteertetet
232434234
erewesdfsfsfs
0234342343
-|
jdhg3875jdfsgfd
sjdhfdbfjds
347674657435
-|

Erwartetes Ergebnis in Datei 1

wertretr
ewretrtret
1212132323
000232
-|

Erwartetes Ergebnis in Datei 2

ereteertetet
232434234
erewesdfsfsfs
0234342343
-|

Erwartetes Ergebnis in Datei 3

jdhg3875jdfsgfd
sjdhfdbfjds
347674657435
-|
63
user1499178

Ein Liner, keine Programmierung. (außer dem regulären Ausdruck usw.)

csplit --digits=2  --quiet --prefix=outfile infile "/-|/+1" "{*}"
78
ctrl-alt-delor
awk '{print $0 " -|"> "file" NR}' RS='-\\|'  input-file

Erklärung (bearbeitet): 

RS ist der Datensatztrenner, und diese Lösung verwendet eine gnu awk-Erweiterung, die es erlaubt, mehr als ein Zeichen zu enthalten. NR ist die Datensatznummer. 

Die print-Anweisung druckt einen Datensatz gefolgt von " -|" in eine Datei, die die Datensatznummer im Namen enthält.

29
William Pursell

Debian hat csplit, aber ich weiß nicht, ob dies allen/den meisten/anderen Distributionen gemeinsam ist. Wenn nicht, sollte es nicht zu schwer sein, die Quelle aufzuspüren und sie zu kompilieren ...

7
twalberg

Ich habe ein etwas anderes Problem gelöst, bei dem die Datei eine Zeile mit dem Namen enthält, in den der folgende Text gehen soll. Dieser Perl-Code macht den Trick für mich: 

#!/path/to/Perl -w

#comment the line below for UNIX systems
use Win32::Clipboard;

# Get command line flags

#print ($#ARGV, "\n");
if($#ARGV == 0) {
    print STDERR "usage: ncsplit.pl --mff -- filename.txt [...] \n\nNote that no space is allowed between the '--' and the related parameter.\n\nThe mff is found on a line followed by a filename.  All of the contents of filename.txt are written to that file until another mff is found.\n";
    exit;
}

# this package sets the ARGV count variable to -1;

use Getopt::Long;
my $mff = "";
GetOptions('mff' => \$mff);

# set a default $mff variable
if ($mff eq "") {$mff = "-#-"};
print ("using file switch=", $mff, "\n\n");

while($_ = shift @ARGV) {
    if(-f "$_") {
    Push @filelist, $_;
    } 
}

# Could be more than one file name on the command line, 
# but this version throws away the subsequent ones.

$readfile = $filelist[0];

open SOURCEFILE, "<$readfile" or die "File not found...\n\n";
#print SOURCEFILE;

while (<SOURCEFILE>) {
  /^$mff (.*$)/o;
    $outname = $1;
#   print $outname;
#   print "right is: $1 \n";

if (/^$mff /) {

    open OUTFILE, ">$outname" ;
    print "opened $outname\n";
    }
    else {print OUTFILE "$_"};
  }
5

Sie können auch awk verwenden. Ich bin mit awk nicht sehr vertraut, aber das folgende schien für mich zu funktionieren. Es generiert part1.txt, part2.txt, part3.txt und part4.txt. Beachten Sie, dass die letzte hier generierte partn.txt-Datei leer ist. Ich bin mir nicht sicher, wie man das beheben kann, aber ich bin mir sicher, dass dies mit ein paar kleinen Änderungen erledigt werden könnte. Irgendwelche Vorschläge?

awk_pattern Datei:

BEGIN{ fn = "part1.txt"; n = 1 }
{
   print > fn
   if (substr($0,1,2) == "-|") {
       close (fn)
       n++
       fn = "part" n ".txt"
   }
}

Bash-Befehl:

awk -f awk_pattern input.file

2
rkyser

Verwenden Sie csplit, wenn Sie es haben. 

Wenn nicht, aber Sie haben Python ... verwenden Sie kein Perl.

Faules Lesen der Datei

Ihre Datei ist möglicherweise zu groß, um alle auf einmal im Arbeitsspeicher zu halten - zeilenweises Lesen ist vorzuziehen. Angenommen, die Eingabedatei heißt "samplein":

$ python3 -c "from itertools import count
with open('samplein') as file:
    for i in count():
        firstline = next(file, None)
        if firstline is None:
            break
        with open(f'out{i}', 'w') as out:
            out.write(firstline)
            for line in file:
                out.write(line)
                if line == '-|\n':
                    break"
1
Aaron Hall

Der folgende Befehl funktioniert für mich. Ich hoffe es hilft.

awk 'BEGIN{file = 0; filename = "output_" file ".txt"}
    /-|/ {getline; file ++; filename = "output_" file ".txt"}
    {print $0 > filename}' input
1
Thanh

Hier ist ein Python 3-Skript, das eine Datei in mehrere Dateien aufteilt, basierend auf einem Dateinamen, der von den Trennzeichen bereitgestellt wird. Beispiel Eingabedatei:

# Ignored

######## FILTER BEGIN foo.conf
This goes in foo.conf.
######## FILTER END

# Ignored

######## FILTER BEGIN bar.conf
This goes in bar.conf.
######## FILTER END

Hier ist das Skript:

#!/usr/bin/env python3

import os
import argparse

# global settings
start_delimiter = '######## FILTER BEGIN'
end_delimiter = '######## FILTER END'

# parse command line arguments
parser = argparse.ArgumentParser()
parser.add_argument("-i", "--input-file", required=True, help="input filename")
parser.add_argument("-o", "--output-dir", required=True, help="output directory")

args = parser.parse_args()

# read the input file
with open(args.input_file, 'r') as input_file:
    input_data = input_file.read()

# iterate through the input data by line
input_lines = input_data.splitlines()
while input_lines:
    # discard lines until the next start delimiter
    while input_lines and not input_lines[0].startswith(start_delimiter):
        input_lines.pop(0)

    # corner case: no delimiter found and no more lines left
    if not input_lines:
        break

    # extract the output filename from the start delimiter
    output_filename = input_lines.pop(0).replace(start_delimiter, "").strip()
    output_path = os.path.join(args.output_dir, output_filename)

    # open the output file
    print("extracting file: {0}".format(output_path))
    with open(output_path, 'w') as output_file:
        # while we have lines left and they don't match the end delimiter
        while input_lines and not input_lines[0].startswith(end_delimiter):
            output_file.write("{0}\n".format(input_lines.pop(0)))

        # remove end delimiter if present
        if not input_lines:
            input_lines.pop(0)

Zum Schluss, wie Sie es ausführen:

$ python3 script.py -i input-file.txt -o ./output-folder/
1
ctrlc-root

Hier ist ein Perl-Code, der die Sache erledigt

#!/usr/bin/Perl
open(FI,"file.txt") or die "Input file not found";
$cur=0;
open(FO,">res.$cur.txt") or die "Cannot open output file $cur";
while(<FI>)
{
    print FO $_;
    if(/^-\|/)
    {
        close(FO);
        $cur++;
        open(FO,">res.$cur.txt") or die "Cannot open output file $cur"
    }
}
close(FO);
0
amaksr
cat file| ( I=0; echo -n "">file0; while read line; do echo $line >> file$I; if [ "$line" == '-|' ]; then I=$[I+1]; echo -n "" > file$I; fi; done )

und die formatierte Version:

#!/bin/bash
cat FILE | (
  I=0;
  echo -n"">file0;
  while read line; 
  do
    echo $line >> file$I;
    if [ "$line" == '-|' ];
    then I=$[I+1];
      echo -n "" > file$I;
    fi;
  done;
)
0
mbonnin