2015-05-21 5 views
0

У меня есть огромный файл, содержащий несколько подсетей, например:Split несколько похожих строк в двух отдельных файлах с Bash

234.245.34.324/24 
234.214.23.34/24 
234.344.234.14/24 
234.214.234.314/24 
234.245.34.324/23 
234.214.23.34/22 
234.344.234.14/22 
234.214.234.314/23 
234.245.34.324/24 
234.214.23.34/20 
234.344.234.14/21 
234.214.234.314/20 

все они с разными IP-адресами и одной подсети, например, у меня есть 2340 подсеть с /24.

Теперь я хочу эти разделить на 2 файлов, где 50% всех /24 расколов в каждом файле, то же самое для /23, /22/21 т.д.

Я знаю, что я могу разделить с split -l но это будет только дай мне линию. Цель состоит в том, чтобы получить одинаковое количество подсетей в оба файла.

Это должно быть сделано в Linux bash, так как оно будет автоматизировано.

Кто-нибудь знает, как это сделать?

+0

извините, забыл сказать, что это должно быть сделано в linux bash, так как оно будет автоматизировано – kryd

+2

Что вы пробовали? Пожалуйста, прочитайте [Как задать хороший вопрос?] (Http://stackoverflow.com/help/how-to-ask). – DavidPostill

+0

Лично я начинал с фильтрации в файл (предположительно во временном каталоге) на размер маски - т. Е. файл с именем '20' со всеми'/20 's, файл с именем' 19' со всеми '/ 19' s и т. д .; это тривиально делать с GNU awk; то вы просто берете половину каждого файла. –

ответ

1

Если у вас есть Баш 4,3 доступны, реализация, которая позволяет избежать использования временных файлов может выглядеть примерно так:

#!/usr/bin/env bash 
#  ^- important: use bash, not sh, as shell 

# sort into an array per mask length 
declare -A masklens=() 
while IFS=/ read -r addr masklen; do 
    [[ $addr ]] || continue 
    masklens[$masklen]=1 
    declare -a "addrs_${masklen}" 
    declare -n addrs="addrs_${masklen}" 
    addrs+=("$addr") 
done 

exec 3>"$1" 4>"$2" # open output files 
for masklen in "${!masklens[@]}"; do 
    declare -n addrs="addrs_${masklen}" 
    fmt="%s/${masklen}\n" 
    printf "$fmt" "${addrs[@]:0:(${#addrs[@]} + 1)/2}" >&3 
    if ((${#addrs[@]} > 1)); then 
    printf "$fmt" "${addrs[@]:(${#addrs[@]} + 1)/2}" >&4 
    fi 
done 
exec 3>&- 4>&- # close output files 

... вызывается, как ...

$ splitfiles out1 out2 <infile 
+0

на самом деле у меня не было bash 3.4, поэтому я получил несколько ошибок от объявления, но, похоже, он делает то, что должен. я должен был удалить повторяющиеся строки также с uniq -u, но, похоже, сделал магию, спасибо – kryd

+0

Это, конечно, не будет работать без 'declare -n'; ваш результат будет неправильным (он будет строить один большой массив, а не массив на длину маски и разделять их по отдельности). –

+0

... также вы можете получить дубликат вывода (скопированный для каждого увиденного маской), если вы используете это в bash без 'declare -n'. –

Смежные вопросы