divide o arquivo em N partes com o mesmo nome, mas diferentes diretórios de destino

6

Eu quero dividir sourcefile.txt que contém 10000 linhas (aumentando todos os dias) em 30 arquivos iguais. Eu tenho diretórios chamados prog1 to prog30 e gostaria de salvar dividir o arquivo nesses diretórios com o mesmo nome de arquivo. Por exemplo, /prog1/myfile.txt , /prog2/myfile.txt to /prog30/myfile.txt .

Aqui está o meu script chamado divide.sh é executado no diretório prog

#!/bin/bash
programpath=/home/mywebsite/project/a1/
array=/prog1/
totalline=$(wc -l < ./sourcefile.txt)   
divide="$(( $totalline / 30 ))"   
split --lines=$divide $./prog1/myfile.txt    
exit 1
fi
    
por danone 30.10.2017 / 12:14

6 respostas

1

Versão Sed para diversão:

lines=$(wc -l <sourcefile.txt)
perfile=$(( (lines+29)/30 ))     # see https://www.rfc-editor.org/rfc/rfc968.txt
last=0
sed -nf- sourcefile.txt <<EOD
$(while let $((last<lines)); do 
        mkdir -p prog$((last/perfile+1))
        echo $((last+1)),$((last+perfile)) w prog$((last/perfile+1))/myfile.txt
        : $((last+=perfile))
        done)
EOD
    
por 30.10.2017 / 15:33
4
#!/bin/bash

# assuming the file is in the same folder as the script
INPUT=large_file.txt
# assuming the folder called "output" is in the same folder
# as the script and there are folders that have the patter
# prog01 prog02 ... prog30
# create that with mkdir output/prog{01..30} 
OUTPUT_FOLDER=output

OUTPUT_FILE_FORMAT=myfile

# split 
# -n -> 30 files
# $OUTPUT_FILE_FORMAT -> should start with this pattern
# --numeric-suffixes=1 -> end of file name should start from 01 
split -n 30 $INPUT $OUTPUT_FILE_FORMAT --numeric-suffixes=1

# move all files to their repective directories
for i in {01..30} 
do
    mv $OUTPUT_FILE_FORMAT$i $OUTPUT_FOLDER/prog$i/myfile.txt
done

echo "done :)"

exit

O comando split é mais que suficiente para essa tarefa. No entanto, a solução aqui exige que você faça com que os nomes das pastas comecem de prog01 e não prog1

    
por 30.10.2017 / 12:53
3

A solução awk ( N aqui é igual a 30 arquivos):

awk 'BEGIN{ cmd="wc -l <sourcefile.txt"; cmd|getline l; l=int((l+29)/30); close(cmd) } 
    NR%l==1{trgt=sprintf("prog%d",((++c)))}{print >trgt"/myfile.txt"}' sourcefile.txt

Ou deixe o shell executar e retornar o número de linhas em sourcefile.txt e passar para awk como sugerido por jthill .

awk 'NR%l==1{trgt=sprintf("prog%d",((++c)))}{print >trgt"/myfile.txt"}' 
    l=$(( ($(wc -l <sourcefile.txt)+29)/30 )) sourcefile.txt
    
por 30.10.2017 / 14:52
2
Solução

split + bash :

lines=$(echo "t=$(wc -l ./sourcefile.txt | cut -d' ' -f1); d=30; if(t%d) t/d+1 else t/d" | bc)
split -l $lines ./sourcefile.txt "myfile.txt" --numeric-suffixes=1

for f in myfile.txt[0-9]*; do 
    dir_n="prog"$(printf "%d" "${f#*txt}")  # constructing directory name
    mv "$f" "$dir_n/myfile.txt"
done

Supondo que você já tenha pastas chamadas prog1 para prog30 (como você mencionou)

  • lines - contém o número inteiro de linhas por arquivo de saída

    • t - número total de linhas de arquivo ./sourcefile.txt
    • d=30 é um divisor
  • A opção
  • --numeric-suffixes=1 - split diz para usar sufixos numéricos que começam em 1

por 30.10.2017 / 12:53
1

Etapas

  1. conte as linhas no arquivo e divida por 30 lines = cat ${file} | wc -l

  2. obtenha a quantidade de arquivos que você precisa (o bash irá arredondar para um inteiro) numOfFiles = ${lines} / 30

  3. use dividir para dividir o arquivo split -l ${lines} -d --additional-suffix=-filename.extension ${file}

Resultado esperado

x01-filename.extension, x02-filename.extension ... xN-filename.extension

Envolva-o em um loop for para processar mais de um arquivo por vez

#!/bin/bash    
for FILE in $(find ${pathToWorkingDir} -type f -name "filename.extension")
do
    split -l ${lines} -d --additional-suffix=-filename.extension ${file}
    if [ $? -eq 0 ]; then
        echo "${file} splitted file correctly"
    else
        echo "there was a problem splitting ${file}"
        exit 1 #we exit with an error code
    fi
done
exit 0 #if all processed fine we exit with a success code
    
por 30.10.2017 / 12:51
0

Paralelizado com o Paralelo GNU:

parallel -j30 -a sourcefile.txt --pipepart --block -1 cat '>'prog{#}/myfile.txt

Isso executará 30 trabalhos em paralelo, dividindo sourcefile.txt em uma parte por trabalho (ou seja, 30) e fornecerá as partes para cat que salvam em prog{jobnumber}/myfile.txt .

    
por 17.11.2017 / 01:18