한 파일의 내용을 다른 파일로 바꾸려고 합니다.
입력 파일 Test.txt
:
HLRSN = 3
IMSI = 404212109727229
KIVALUE = A24AD11812232B47688ADBF15CE05CA9
K4SNO = 1
CARDTYPE = SIM
ALG = COMP128_3
HLRSN = 3
IMSI = 404212109727230
KIVALUE = A24AD11812232B47688ADBF15CE05CB8
K4SNO = 1
CARDTYPE = SIM
ALG = COMP128_3
HLRSN = 3
IMSI = 404212109727231
KIVALUE = A24AD11812232B47688ADBF15CE05CD6
K4SNO = 1
CARDTYPE = SIM
ALG = COMP128_3
다른 텍스트 파일에서 원하는 출력:
3,404212109727229,A24AD11812232B47688ADBF15CE05CA9,1,SIM,COMP128_3
3,404212109727230,A24AD11812232B47688ADBF15CE05CB8,1,SIM,COMP128_3
3,404212109727231,A24AD11812232B47688ADBF15CE05CD6,1,SIM,COMP128_3
답변1
간단히:
awk -v RS= -v OFS=, '{print $3,$6,$9,$12,$15,$18}'
비어있는기록 구분 기호( RS=
) 할 수 있게 하다단락 모드여기서 레코드는 일련의 빈 줄로 구분됩니다. 레코드 내부에는 기본 필드 구분 기호가 적용되므로(레코드는 공백으로 구분됨) 각 레코드에서 관심 있는 필드는 3번째, 6번째, 9번째...
우리는 변한다산출필드 구분 기호는 쉼표 문자( OFS=,
)이며 관심 있는 필드를 인쇄합니다.
답변2
일방 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
입력 필드 구분 기호를 사용합니다read
.- 파일의 끝을 읽을 때까지 파일의 각 줄을 읽고 마지막 필드의 값을 변수로 설정합니다
val
. if [ ! -z "$val" ]
: 변수의 길이가$val
0이 아닌지 확인하기 위해 공백을 제거$val
하고 배열에 푸시합니다out
.- 길이가
$val
0이면, 즉 빈 줄이나 파일 끝이 표시되면 배열의 모든 요소를out
변수 tmp에 할당한 다음 모든 공백 변수를 우리가 설계한 출력 기록 구분 기호tmp
로 바꿉니다.,
out
추가 작업을 위해 null로 설정하세요 .
또 다른 깨끗하고 짧은 솔루션은 다음을 사용하는 것입니다 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
답변3
다음을 파일에 저장합니다(예 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 형식을 제공합니다.
답변4
사용밀러( mlr
) 우리는 단일 줄 바꿈으로 구분된 필드를 포함하고 등호로 구분된 키-값 쌍을 포함하는 이중 줄 바꿈으로 구분된 레코드로 데이터를 읽을 수 있습니다. 추가 공백과 빈 열(이러한 구분 기호를 사용하여 데이터를 읽은 결과 각 필드 값의 시작 부분에 공백이 추가됨)을 제거한 다음 이를 CSV로 변환할 수 있습니다.
$ mlr --ips = --ifs lf --irs lflf --ocsv clean-whitespace then remove-empty-columns Test.txt
HLRSN,IMSI,KIVALUE,K4SNO,CARDTYPE,ALG
3,404212109727229,A24AD11812232B47688ADBF15CE05CA9,1,SIM,COMP128_3
3,404212109727230,A24AD11812232B47688ADBF15CE05CB8,1,SIM,COMP128_3
3,404212109727231,A24AD11812232B47688ADBF15CE05CD6,1,SIM,COMP128_3
출력에 CSV 헤더를 포함하지 않으려면 이 옵션을 mlr
함께 사용하십시오 -N
. Miller는 포함된 구분 기호나 따옴표가 포함된 모든 필드를 자동으로 인용합니다.