Похож ex
запускается в последней строке - ex -c '1' -c '?bar' -c 'visual' test.txt
перемещает курсор в последнюю строку.
Решение bash
:
declare -a out
EOF=false
IFS=$'='
until $EOF; do
read -r skip val || EOF=true
if [ ! -z "$val" ]
then
out+=("${val//[[:space:]]/}")
else
tmp="${out[@]}"
printf '%s\n' "${tmp// /,}"
out=()
fi
done < file
Как это работает
out
для хранения выходной строки, установить переменную EOF
, чтобы отслеживать конец файла, IFS
для разделителя входных полей для чтения
. val
. если [! -z "$ val"]
: проверить, не равна ли длина переменной $ val
нулю, мы удаляем пробел в $ val
, помещаем его в массив out
. $ val
равна нулю, что означает, что мы получаем пустую строку или конец файла, мы назначаем весь элемент массива out
переменной tmp, затем заменяем всю пространственную переменную tmp
от ,
, нашего разработанного разделителя перекодирования вывода. из
в ноль для следующей работы. Другое решение, более краткое, более короткое для вас - использование perl
:
$ perl -F'=' -anle '
BEGIN { $, = "," }
push @out,$F[-1] if @F;
print @{[map {s/\s// && $_} @out]} and @out = ()
if /^$/ or eof;
' file
3,404212109727229,A24AD11812232B47688ADBF15CE05CA9,1,SIM,COMP128_3
3,404212109727230,A24AD11812232B47688ADBF15CE05CB8,1,SIM,COMP128_3
3,404212109727231,A24AD11812232B47688ADBF15CE05CD6,1,SIM,COMP128_3
Если все блоки имеют точно одинаковый формат (одинаковые имена полей, в одном и том же порядке), то можно использовать awk в "абзацевом режиме", и вывести нужный номер поля в каждом блоке. Если вокруг одинаковых знаков всегда есть пробелы, а значения никогда не содержат пробелов, можно полагаться на поля, разделенные пробелами.
awk -v RS= -v ORS=',' '{print $3, $6, $9, $12, $15, $18}'
Если вы можете полагаться на порядок и наличие полей, но не на пробелы, то вам понадобится немного разобрать, чтобы разделить поля на равные знаки.
awk -v RS= -F '\n' '{
for (i = 1; i <= NF; i++) {
sub(/[^=]*= */, "", $i);
printf "%s%s", $i, (i==NF ? "\n" : ",");
}
}'
Вот метод Perl:
perl -000 -ne '
$, = ","; $\ = "\n";
@kv = split /\n| *= */;
print @kv[grep {$_%2} 0..$#kv];
'
Если поля в блоках могут выходить из порядка и вам всегда нужен определенный порядок в качестве вывода, вам нужно будет хранить поля и распечатывать их в правильном порядке в конце каждого абзаца. В awk это проще сделать в режиме строки, чем в параграфе.
awk -v OFS=',' '
match($0, / *= */) {a[substr($0,1,RSTART-1)] = substr($0,RSTART+RLENGTH)}
/^$/ {print a["HLRSN"], a["IMSI"], a["KIVALUE"], a["K4SNO"], a["CARDTYPE"], a["ALG"]; split("", a)}
END {print a["HLRSN"], a["IMSI"], a["KIVALUE"], a["K4SNO"], a["CARDTYPE"], a["ALG"]}
'
Это одна строка в Perl.
perl -000 -F'/\n|\s*=\s*/' -ane '%F = @F; $\ = "\n"; $, = ","; print @F{qw(HLRSN IMSI KIVALUE K4SNO CARDTYPE ALG)}'
Сохраните следующее в файл (например, split.awk
)
BEGIN {
RS="\n\n";
FS="\n";
ORS=",";
}
{
for (i=1;i<=NF;i++)
{
split($i, sf, "= ")
print sf[2]
}
printf "\n"
}
Затем запустите:
awk -f split.awk Test.txt
Или запустите всю команду как одну строку:
awk 'BEGIN {RS="\n\n";FS="\n";ORS=",";}{for(i=1;i<=NF;i++){split($i, sf, "= ")print sf[2]}printf "\n"}' Test.txt
Это работает следующим образом:
Блок BEGIN
запускается один раз в начале и устанавливает запись разделитель ( RS
) для двух символов новой строки и разделитель полей ( FS
) для одной новой строки. Разделитель выходных записей ( ORS
) установлен в запятую.
Затем он перебирает каждое поле в записи ( NF
- количество полей в текущей записи) и разбивает его на «=».
Затем он печатает правую часть этого разделения с запятой между ними ( ORS
)
После каждой строки он печатает новую строку, чтобы дать вам формат CSV.
Просто:
awk -v RS= -v OFS=, '{print $3,$6,$9,$12,$15,$18}'
Пустой разделитель записей ( RS =
) включает режим абзацев , в котором записи разделяются последовательности пустых строк. Внутри записи применяется разделитель полей по умолчанию (записи разделяются пробелами), поэтому в каждой записи интересующие нас поля - это 3-е, 6-е, 9-е ...
Мы изменяем вывод разделитель полей на запятую ( OFS =,
) и вывести интересующие нас поля.
Основываясь на других ответах... Мне потребовалась небольшая модификация, поскольку мне нужен был заголовок столбца в конечном CSV-файле. Вот мое awk-решение:
awk -v RS= -v FS='\n' '
NR==1 {
for (i=1; i<=NF; i++) {
split($i,line,"= ");
printf "%s%s", line[1], (i==NF ? "\n" : ",");
}
}
{
for (i=1; i<=NF; i++) {
split($i,line,"= ");
printf "%s%s", line[2], (i==NF ? "\n" : ",");
}
}'
Как и в других ответах, здесь читается весь блок (до пустой строки) по полям, затем каждое поле снова разделяется с помощью split(). Единственная разница в том, что для первой записи печатается часть до '=', а во втором цикле for-loop печатается правая часть для всех записей.