2012-07-03 11 views
50

के आधार पर एक फ़ाइल को एकाधिक फ़ाइलों में विभाजित करें मेरे पास प्रत्येक अनुभाग के बाद -| के साथ एक फ़ाइल है ... प्रत्येक अनुभाग के लिए यूनिक्स का उपयोग करके अलग-अलग फ़ाइलों को बनाने की आवश्यकता है। इनपुट फ़ाइलडेलीमीटर

उदाहरण

wertretr 
ewretrtret 
1212132323 
000232 
-| 
ereteertetet 
232434234 
erewesdfsfsfs 
0234342343 
-| 
jdhg3875jdfsgfd 
sjdhfdbfjds 
347674657435 
-| 
फ़ाइल में

अपेक्षित परिणाम 1

wertretr 
ewretrtret 
1212132323 
000232 
-| 
फ़ाइल में

अपेक्षित परिणाम 2

ereteertetet 
232434234 
erewesdfsfsfs 
0234342343 
-| 
फ़ाइल में

अपेक्षित परिणाम 3

jdhg3875jdfsgfd 
sjdhfdbfjds 
347674657435 
-| 
+1

क्या आप कोई प्रोग्राम लिख रहे हैं या आप कमांड लाइन उपयोगिताओं का उपयोग करके ऐसा करना चाहते हैं? कमांड लाइन यूटिलिटीज का उपयोग कर – rkyser

+1

बेहतर होगा .. – user1499178

+0

आप अजीब का उपयोग कर सकते हैं, ऐसा करने के लिए 3 या 4 लाइन प्रोग्राम लिखना आसान होगा। दुर्भाग्य से मैं अभ्यास से बाहर हूं। –

उत्तर

6

डेबियन में csplit है, लेकिन मुझे नहीं पता कि यह सभी/अधिकांश/अन्य वितरणों के लिए आम है या नहीं। यदि नहीं है, हालांकि, यह नहीं भी स्रोत नज़र रखने और उसे संकलित करने के लिए कठिन हो सकता है चाहिए ...

+1

मैं सहमत हूं। मेरा डेबियन बॉक्स कहता है कि सीएसप्लिट gnu coreutils का हिस्सा है। तो किसी भी जीएनयू ऑपरेटिंग सिस्टम, जैसे कि सभी जीएनयू/लिनक्स डिस्ट्रोज़ में यह होगा। विकिपीडिया ने सीएसप्लिट पेज पर 'एकल यूनिक्स® विशिष्टता, अंक 7' का भी उल्लेख किया है, इसलिए मुझे संदेह है कि आपको यह मिल गया है। –

+2

चूंकि ['csplit'] (http://pubs.opengroup.org/onlinepubs/9699919799/utilities/csplit.html) POSIX में है, मैं उम्मीद करता हूं कि यह अनिवार्य रूप से सभी यूनिक्स-जैसी प्रणालियों पर उपलब्ध हो। –

+1

हालांकि सीएसप्लिट POISX है, समस्या (ऐसा लगता है कि यह मेरे सामने बैठे उबंटू सिस्टम पर एक परीक्षण कर रहा है) यह है कि इसे एक और आधुनिक रेगेक्स वाक्यविन्यास का उपयोग करने के लिए कोई स्पष्ट तरीका नहीं है। तुलना करें: 'csplit --prefix सोना-डेटा -"/^ == * $/'बनाम csplit --prefix सोना-डेटा -"/^ = + $/'। कम से कम जीएनयू grep '-e' है। – new123456

0
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) 

और स्वरूपित संस्करण:

#!/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; 
) 
+3

हमेशा के रूप में, ['बिल्ली' Useless है] (http://www.iki.fi/era/unix/award.html)। – tripleee

2

तुम भी awk उपयोग कर सकते हैं। मैं अजीब से बहुत परिचित नहीं हूं, लेकिन निम्नलिखित मेरे लिए काम करता प्रतीत होता है। यह part1.txt, part2.txt, part3.txt, और part4.txt उत्पन्न हुआ। ध्यान दें, कि आखिरी partn.txt फ़ाइल जो उत्पन्न करती है वह खाली है। मुझे यकीन नहीं है कि यह कैसे ठीक है, लेकिन मुझे यकीन है कि यह थोड़ा tweaking के साथ किया जा सकता है। कोई सुझाव किसी को भी?

awk_pattern फ़ाइल:

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

बैश आदेश:

awk -f awk_pattern input.file

-1

यहाँ एक पर्ल कोड है कि काम करेंगे है

#!/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); 
25
awk '{print $0 " -|"> "file" NR}' RS='-\\|' input-file 
+0

यह वास्तव में बड़ी फ़ाइलों (> 3 जीबी) पर कितना अच्छा काम करता है? मैं अजीब से परिचित नहीं हूँ। – rzetterberg

+0

क्या आप विभिन्न भागों की व्याख्या कर सकते हैं? 'आरएस' क्या है? 'एनआर' क्या है? –

+0

'आरएस' रिकॉर्ड विभाजक है, और यह समाधान एक gnu awk एक्सटेंशन का उपयोग करता है जो इसे एक से अधिक वर्णों की अनुमति देता है। एनआर रिकॉर्ड संख्या है। प्रिंट स्टेटमेंट एक रिकॉर्ड प्रिंट करता है जिसके बाद "- |" उस फ़ाइल में जिसमें उसके नाम पर रिकॉर्ड नंबर है। –

61

एक लाइनर, कोई प्रोग्रामिंग नहीं। (Regexp आदि को छोड़कर)

csplit --digits=2 --quiet --prefix=outfile infile "/-|/+1" "{*}" 
+1

+1 - छोटा:' csplit -n2 -s -b आउटफाइल infile "/ - |/+" "{*}" ' – zb226

+19

@ zb226 मैंने इसे लंबे समय तक किया, इसलिए कि कोई स्पष्टीकरण की आवश्यकता नहीं थी। –

+3

मैं '-elide-blank-files 'जोड़ने का सुझाव देता हूं, अन्यथा अंत में एक खाली फ़ाइल होगी। – luator

0

यह समस्या की तरह मैं के लिए संदर्भ के विभाजन ने लिखा है: http://stromberg.dnsalias.org/~strombrg/context-split.html

$ ./context-split -h 
usage: 
./context-split [-s separator] [-n name] [-z length] 
     -s specifies what regex should separate output files 
     -n specifies how output files are named (default: numeric 
     -z specifies how long numbered filenames (if any) should be 
     -i include line containing separator in output files 
     operations are always performed on stdin 
+0

उह, यह अनिवार्य रूप से मानक 'csplit' उपयोगिता का डुप्लिकेट जैसा दिखता है। [@ रिचर्ड का जवाब] देखें (http://stackoverflow.com/a/11314918/874188)। – tripleee

+0

यह वास्तव में सबसे अच्छा समाधान आईएमओ है। मुझे किसी 98 जी mysql डंप और csplit को किसी कारण से विभाजित करना पड़ा है, मेरी सारी रैम खाती है, और मारे गए हैं। भले ही इसे उस समय एक पंक्ति से मेल खाना पड़े। कुछ समझ नहीं आया। यह पायथन लिपि बहुत बेहतर काम करती है और सभी राम को नहीं खाती है। –

5

मैं एक अलग समस्या है, जहां फ़ाइल के साथ एक पंक्ति है हल वह नाम जहां पाठ का पालन करना चाहिए। यह पर्ल कोड मेरे लिए काम कर देता है: मेरे लिए

#!/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 "$_"}; 
    } 
+0

क्या आप कृपया बता सकते हैं कि यह कोड क्यों काम करता है? मेरे पास यहां वर्णित एक समान स्थिति है - आवश्यक आउटपुट फ़ाइल नाम फ़ाइल के अंदर एम्बेडेड हैं। लेकिन मैं नियमित रूप से perl उपयोगकर्ता नहीं हूं इसलिए इस कोड को समझ में नहीं आता है। – shiri

0

निम्न आदेश काम करता है। आशा करता हूँ की ये काम करेगा। बैश awk 'BEGIN{file = 0; filename = "output_" file ".txt"} /-|/ {getline; file ++; filename = "output_" file ".txt"}{print $0 > filename}' input

1

यहाँ एक अजगर 3 स्क्रिप्ट सीमांकक द्वारा प्रदान की एक फ़ाइल नाम के आधार एकाधिक फ़ाइलों में एक फ़ाइल विभाजन है।उदाहरण इनपुट फ़ाइल:

# Ignored 

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

# Ignored 

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

यहाँ स्क्रिप्ट है:

#!/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) 

अंत में यहाँ कैसे आप इसे चलाने के लिए:

$ python3 script.py -i input-file.txt -o ./output-folder/ 
0

उपयोग csplit आप इसे किया है।

यदि आप नहीं करते हैं, लेकिन आपके पास पाइथन है ... पर्ल का उपयोग न करें।

अपने नमूना फ़ाइल मान लिया जाये कि "samplein" कहा जाता है:

$ python -c "import sys 
for i, c in enumerate(sys.stdin.read().split('-|')): 
    open('out' + str(i), 'w').write(c)" < samplein 

और अब:

$ python -c "import sys 
for i, c in enumerate(sys.stdin.read().split('-|')): 
    open(f'out{i}', 'w').write(c)" < samplein 

आप अजगर 3.5 या कम है, तो आप च-तार उपयोग नहीं कर सकते

$ ls out* 
out0 out1 out2 out3