1

I have a requirement where I'm getting a .txt file in output from some tool and I want to split that into three.

Example text from file:

First line
Second line
23456
45677
45678

Third line
90909
90678

Last line
Z567Z
6787T

Expected outputs:

-> file1.txt

23456
45677
45678

-> file2.txt

90909
90678

-> file3.txt

Z567Z
5677T

Basically, files will have 5 digit numeric/alphanumeric values which we want to use, and text in between works as identifier to split file into multiple files.

I'm looking to use awk or sed command to do this.

0

3 Answers 3

6

If this isn't all you need:

$ awk '
    /^[[:alnum:]]{5}$/ {
        if ( !inBlock++ ) {
            close(out)
            out = "file" (++cnt) ".txt"
        }
        print > out
        next
    }
    { inBlock = 0 }
' file

$ head file?.txt
==> file1.txt <==
23456
45677
45678

==> file2.txt <==
90909
90678

==> file3.txt <==
Z567Z
6787T

then edit your question to provide clearer requirements and more truly representative sample input/output.

3
  • how can I remove 5 digit restriction? - if I have to go for more digits but not exact. i.e., <50
    – marwari
    Feb 22, 2022 at 18:28
  • 1
    Change {5} to whatever interval you like, e.g. it sounds like you might want {5,49} or {1,49}. See "interval expression" in the POSIX EREs spec.
    – Ed Morton
    Feb 22, 2022 at 18:46
  • 1
    Great! this is all I wanted. Thanks for the link.
    – marwari
    Feb 22, 2022 at 19:04
1

Here is ugly one liner:

grep -v '[:alpha:]' test.txt | sed "s/^$/==/g" | split -p "=="

Note: This will generate 3 or more files (xa*) as per "==" pattern.

You can further use for loop to remove "==" (sed 's/=//g' xa* | grep -v "^$") if there is any.

1
  • 1
    ITYM [[:alpha:]], not just [:alpha:].
    – Ed Morton
    Feb 19, 2022 at 14:27
0

You can use from the GNU tool chest grep+csplit

grep -v '\W' < your_file |
csplit --suppress-matched \
  -szn1 -f file -b '%d.txt' \
  - '/^$/' '{*}'

awk in paragraph mode where record are separated by at least one blank line.

awk -v RS= '
match($0,/\n[[:alnum:]]+(\n|$)/) {
  out = "file" NR ".txt"
  print substr($0,1+RSTART) > out
  close(out)
}
' your_file

Using GNU sed we first generate the sed code from the input data to operate upon to generate the desired output files.

sed -En '
  1{x;s/.*/123/;x;}
  /^\w+$/{=;$z;}
  /^$/{
    G
    s/^(.)(.)(.*)/wfile\2.txt\1\3/
    P;s/.*\n//;h
  }
' your_file | sed -Ee '
  :a;N;/\n[0-9]+$/ba
  s/\n(.*\n)?([0-9])/,\2/
  s/\n//
' - | sed -nf - your_file

Output files: in case of csplit, the file numbering begins from zero.

==> file1.txt <==
23456
45677
45678

==> file2.txt <==
90909
90678

==> file3.txt <==
Z567Z
6787T

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .