Dividindo um único arquivo em vários arquivos com base em strings correspondentes no Linux

Dividindo um único arquivo em vários arquivos com base em strings correspondentes no Linux

Eu tenho um arquivo que tem conteúdo mais ou menos assim:

Arquivo.txt:

661###############20160315###
###########################
###########################
661###############20160316###
###########################
661###############20160317###
###########################

Quero dividir este único arquivo em vários arquivos com base na string inicial "661" e na data (2016MMDD) e renomear o arquivo dividido como 20160315.txt, 20160316.txt e assim por diante. Por exemplo, cada arquivo dividido terá:

20160315.txt terá:

661###############20160315########
################################
################################

20160316.txt terá:

661###############20160316########
################################

20160317.txt terá:

661###############20160317#######
###############################

Existe um comando awk que pode fazer isso?

Responder1

Tenho certeza de que existe um awkcomando que pode fazer isso, não tenho habilidade suficiente para awkencontrar uma solução. Enquanto isso, você poderia usar algo assim:

#!/bin/bash

csplit -z tosplit /661/ {*}

for file in xx*; do
    newName=$(egrep -o '2[0-9]{7}' $file)
    mv $file $newName.txt
done
rm -rf xx*

Onde tosplitestá este arquivo (seu arquivo de exemplo):

661###############20160315###
###########################
###########################
661###############20160316###
###########################
661###############20160317###
###########################

Depois de executar este script (no mesmo diretório do tosplitarquivo), recebo três arquivos:

ls 2016031*
20160315.txt  20160316.txt  20160317.txt

... assim:

cat 20160315.txt 
661###############20160315###
###########################
###########################

cat 20160316.txt 
661###############20160316###
###########################

cat 20160317.txt 
661###############20160317###
###########################

Você também pode (?) usar csplitpara nomear os arquivos, mas isso também está acima do meu salário!

Responder2

Com awkalgo como

awk '/^661/{f=substr($0,match($0,/2016[0-9]{4}/),8)".txt"}{print>>f}' file.txt

pode funcionar para você.

Basicamente as peças são:

/^661/{...} # on each line starting with 661

match($0,/2016[0-9]{4}/) # find the index of the date (2016MMDD) in current line

substr($0,match($0,/2016[0-9]{4}/),8) # extract the the date in the current line

f=substr($0,match($0,/2016[0-9]{4}/),8)".txt" # assign it to f and append ".txt"

{print>>f} # redirect the content of the current line into the file named by f

Com uma awkimplementação tradicional você pode ter que substituir oexpressões de intervalopara:

awk '/^661/{f=substr($0,match($0,/2016[01][0-9][0-9][0-9]/),8)".txt"}{print>>f}' file.txt

Dependendo do seu caso de uso, você também pode querer alterar ocomportamento do redirecionamento, ou seja , print>fvs.print>>f

informação relacionada