Bash создает несколько разделенных запятыми списков, ограниченных N элементами из одного большего списка - PullRequest
0 голосов
/ 01 октября 2019

У меня огромный список (несколько миллионов строк) значений этого типа:

abcx437u2bz;dhnauih41291
bbvcae13421;fjhllalsi432
...

Мне нужно построить множество небольших списков следующим образом:

abcx437u2bz,bbvcae13421,...

, поэтому толькоПервую часть перед ; необходимо взять, а значения следует разделить на меньшие списки, разделенные запятыми, ограниченные 1000 элементами в одной строке.

Как я могу выполнить это в скрипте bash, чтобы я мог автоматизировать эту задачу?

Ответы [ 5 ]

1 голос
/ 01 октября 2019
cut -d';' -f1 input_file | paste -sd, | sed 's/,/\n/100;P;D'

Сначала с cut извлеките первое поле. Затем объедините все поля, используя запятую с paste. Затем используйте sed, чтобы заменить каждые 100 запятых символом новой строки, как в этом сообщении .

Протестировано с:

cat <<EOF >input_file
abcx437u2bz;dhnauih41291
bbvcae13421;fjhllalsi432
a;b
c;d
e;f
g;e
1;2
3;4
5;6
7;8
9;0
a;s
d;f
g;h
EOF
cut -d';' -f1 input_file | paste -sd, | sed -E 's/,/\n/4;P;D'

выходами:

abcx437u2bz,bbvcae13421,a,c
e,g,1,3
5,7,9,a
d,g
1 голос
/ 01 октября 2019

Очень компактное решение

C=1;MAXPERLINE=1000;SEP="";RESULT="";for i in $(<hugeListFile);do FIRST=$(echo "$i" | cut -f1 -d\;); RESULT=$RESULT$SEP$FIRST;SEP=",";[ $C -eq $MAXPERLINE ] && { echo "$RESULT";(( C=1 )); RESULT="";SEP=""; };(( C=$C+1 ));done; echo "$RESULT"
1 голос
/ 01 октября 2019

Perl однострочный:

perl -F';' -lane 'BEGIN { $, = "," }
                  push @vals, $F[0];
                  if (@vals == 1000) { print @vals; @vals = () }
                  END { print @vals if @vals }' inputfile
1 голос
/ 01 октября 2019

Еще один в awk (для трех строк в строке. Для тысячи в строке заменить все NR%3 на NR%1000):

$ awk -F\; '{
    printf "%s%s%s",(NR%3==1?"":","),$1,(NR%3==0?ORS:"")
}
END {
    printf "%s",(NR%3==0?"":ORS)
}' file file file                # emulating more data with multiple calls to the file

Вывод для 6 записей данных:

abcx437u2bz,bbvcae13421,abcx437u2bz
bbvcae13421,abcx437u2bz,bbvcae13421
$

Вывод для 4 записей данных (2 обращения к файлу):

abcx437u2bz,bbvcae13421,abcx437u2bz
bbvcae13421
$
1 голос
/ 01 октября 2019

С помощью bash вы можете сказать что-то вроде:

nr=1
while IFS=";" read -r a rest; do
    str+=",$a"
    if (( nr % 1000 == 0 )); then
        echo "${str#,}"
        str=""
    fi
    nr=$(( nr + 1))
done < file.txt
[[ -n $str ]] && echo "${str#,}"

Однако bash может не подойти для работы с огромным файлом, и обработка миллионов строк займет несколько минут.
Вместо этого вы можете сказать awk как:

awk -F";" '{
    str = str "," $1
    if (NR%1000 == 0) {
        print substr(str, 2)
        str = ""
    }
}
END {
    if (length(str)) print substr(str, 2)
}
' file.txt

, что ускорит время выполнения в десятки раз.

...