![특정 구분 기호를 기반으로 txt 파일을 구문 분석하고 CSV 파일로 변환합니다.](https://linux55.com/image/90684/%ED%8A%B9%EC%A0%95%20%EA%B5%AC%EB%B6%84%20%EA%B8%B0%ED%98%B8%EB%A5%BC%20%EA%B8%B0%EB%B0%98%EC%9C%BC%EB%A1%9C%20txt%20%ED%8C%8C%EC%9D%BC%EC%9D%84%20%EA%B5%AC%EB%AC%B8%20%EB%B6%84%EC%84%9D%ED%95%98%EA%B3%A0%20CSV%20%ED%8C%8C%EC%9D%BC%EB%A1%9C%20%EB%B3%80%ED%99%98%ED%95%A9%EB%8B%88%EB%8B%A4..png)
OpenSimStats.txt라는 다음 파일이 있습니다.
TestreportsRootAgentCount=0agent(s)
TestreportsChildAgentCount=0childagent(s)
TestreportsGCReportedMemory=10MB(Global)
TestreportsTotalObjectsCount=0Object(s)
TestreportsTotalPhysicsFrameTime=0ms
TestreportsPhysicsUpdateFrameTime=0ms
TestreportsPrivateWorkingSetMemory=2144MB(Global)
TestreportsTotalThreads=0Thread(s)(Global)
TestreportsTotalFrameTime=89ms
TestreportsTotalEventFrameTime=0ms
TestreportsLandFrameTime=0ms
TestreportsLastCompletedFrameAt=25msago
TestreportsTimeDilationMonitor=1
TestreportsSimFPSMonitor=55.3333320617676
TestreportsPhysicsFPSMonitor=55.4766654968262
TestreportsAgentUpdatesPerSecondMonitor=0persecond
TestreportsActiveObjectCountMonitor=0
TestreportsActiveScriptsMonitor=0
TestreportsScriptEventsPerSecondMonitor=0persecond
TestreportsInPacketsPerSecondMonitor=0persecond
TestreportsOutPacketsPerSecondMonitor=0persecond
TestreportsUnackedBytesMonitor=0
TestreportsPendingDownloadsMonitor=0
TestreportsPendingUploadsMonitor=0
TestreportsTotalFrameTimeMonitor=18.18239402771ms
TestreportsNetFrameTimeMonitor=0ms
TestreportsPhysicsFrameTimeMonitor=0.0106373848393559ms
TestreportsSimulationFrameTimeMonitor=0.17440040409565ms
TestreportsAgentFrameTimeMonitor=0ms
TestreportsImagesFrameTimeMonitor=0ms
TestreportsSpareFrameTimeMonitor=18.1818199157715ms
TestreportsLastReportedObjectUpdates=0
TestreportsSlowFrames=1
이 파일을 다음과 같은 CSV 파일로 변환하고 싶습니다.
TestreportsRootAgentCount,TestreportsChildAgentCount,...,TestreportsSlowFrames
0,0,10,0,0...,1
내 말은:
- 구분 기호 앞뒤의 모든 단어를 제거합니다. 이 경우 구분 기호는 "="입니다.
- 구분 기호 왼쪽에 있는 모든 단어를 한 줄에 쉼표로 구분하여 입력합니다.
- 끝에 새 줄 삽입
- 그런 다음 구분 기호( )
=
뒤에 오는 모든 항목을 입력합니다. 해당 숫자가 쉼표로 구분되는 다른 줄에 숫자만 입력합니다 (숫자 뒤에 단위나 문자 없음). - 그런 다음 새 행을 삽입하십시오.
Linux 쉘 스크립트에서 이를 수행하는 방법에 대한 아이디어/제안이 있습니까? sed 또는 gawk를 사용하여?
답변1
OpenSim에서 영감을 받은 9가지 경로:
sed
게다가 몇 가지 쉘 마법 도 추가됩니다 .
sed 's/=.*//' OpenSimStats.txt | paste -sd, >out.csv
sed 's/.*=//; s/[^0-9]*$//' OpenSimStats.txt | paste -sd, >>out.csv
sed
, 셸 마법 없음 :
sed -n 's/=.*//; 1{ h; b; }; $! H; $ { x; s/\n/,/g; p; }' OpenSimStats.txt >out.csv
sed -n 's/.*=//; 1{ s/[0-9]*$//; h; b; }; s/[^0-9]*$//; $! H; $ { x; s/\n/,/g; p; }' OpenSimStats.txt >>out.csv
조개껍데기 마법과 약간의 도움으로 sed
:
paste -sd, <(cut -d= -f1 OpenSimStats.txt) <(cut -d= -f2 OpenSimStats.txt | sed 's/[^0-9]*$//')
cut
게다가 몇 가지 쉘 마법 도 추가됩니다 .
cut -d= -f1 OpenSimStats.txt | paste -sd, >out.csv
cut -d= -f2 OpenSimStats.txt | sed 's/[^0-9]*$//' | paste -sd, >>out.csv
GNU 사용 datamash
:
sed 's/=/,/; s/[^0-9]*$//' OpenSimStats.txt | datamash -t, transpose
그리고 perl
:
perl -lnE 's/\D+$//o;
($a, $b) = split /=/;
push @a, $a; push @b, $b;
END { $, = ","; say @a; say @b }' OpenSimStats.txt
그리고 grep
:
grep -o '^[^=]*' OpenSimStats.txt | paste -sd, >out.csv
egrep -o '[0-9.]+' OpenSimStats.txt | paste -sd, >>out.csv
그리고 bash
:
#! /usr/bin/env bash
line1=()
line2=()
while IFS='=' read -r a b; do
line1+=("$a")
[[ $b =~ ^[0-9.]+ ]]
line2+=("$BASH_REMATCH")
done <OpenSimStats.txt
( set "${line1[@]}"; IFS=,; echo "$*" ) >out.csv
( set "${line2[@]}"; IFS=,; echo "$*" ) >>out.csv
그리고 awk
:
awk -F= '
NR==1 { a = $1; sub(/[^0-9]+$/, "", $2); b = $2; next }
{ a = a "," $1; sub(/[^0-9]+$/, "", $2); b = b "," $2 }
END { print a; print b }' OpenSimStats.txt
데이터 팬을 위한 열 번째 방법,csvtk
:
csvtk replace -d= -f 2 -p '\D+$' -r '' <OpenSimStats.txt | csvtk transpose
11번 보상 경로 vim
:
:%s/\D*$//
:%s/=/\r/
qaq
:g/^\D/y A | normal dd
:1,$-1 s/\n/,/
"aP
:2,$-2 s/\n/,/
:d 1
:w out.csv
답변2
awk
도움을 드릴 수 있는 곳은 다음과 같습니다:
awk -F= '{a[NR,1]=$1;a[NR,2]=$2}
END{
for(i=1; i<NR; i++){
printf a[i,1] ","
}
print a[i,1];
for(i=1; i<NR; i++){
printf "%s", a[i,2]+0
}
print a[i,2];
}' file
배열은 첫 번째 열의 키와 두 번째 열의 값으로 채워집니다 a
.$1
$2
모든 행을 읽은 후 배열의 모든 요소를 두 번 반복하여 키와 값을 표시합니다.
답변3
Perl 솔루션은 다음과 같습니다.
$ perl -F= -lae '$F[1]=~s/[^0-9]//g; push @h,$F[0]; push @l,$F[1];
END{print join ",",@h; print join ",",@l}' OpenSimStats.txt
TestreportsRootAgentCount,TestreportsChildAgentCount,TestreportsGCReportedMemory,TestreportsTotalObjectsCount,TestreportsTotalPhysicsFrameTime,TestreportsPhysicsUpdateFrameTime,TestreportsPrivateWorkingSetMemory,TestreportsTotalThreads,TestreportsTotalFrameTime,TestreportsTotalEventFrameTime,TestreportsLandFrameTime,TestreportsLastCompletedFrameAt,TestreportsTimeDilationMonitor,TestreportsSimFPSMonitor,TestreportsPhysicsFPSMonitor,TestreportsAgentUpdatesPerSecondMonitor,TestreportsActiveObjectCountMonitor,TestreportsActiveScriptsMonitor,TestreportsScriptEventsPerSecondMonitor,TestreportsInPacketsPerSecondMonitor,TestreportsOutPacketsPerSecondMonitor,TestreportsUnackedBytesMonitor,TestreportsPendingDownloadsMonitor,TestreportsPendingUploadsMonitor,TestreportsTotalFrameTimeMonitor,TestreportsNetFrameTimeMonitor,TestreportsPhysicsFrameTimeMonitor,TestreportsSimulationFrameTimeMonitor,TestreportsAgentFrameTimeMonitor,TestreportsImagesFrameTimeMonitor,TestreportsSpareFrameTimeMonitor,TestreportsLastReportedObjectUpdates,TestreportsSlowFrames
0,0,10,0,0,0,2144,0,89,0,0,25,1,553333320617676,554766654968262,0,0,0,0,0,0,0,0,0,1818239402771,0,00106373848393559,017440040409565,0,0,181818199157715,0,1
이 -a
플래그는 동작을 유사하게 만들고 각 입력 행을 perl
(여기서는 )에 의해 awk
지정된 필드 구분 기호의 배열로 분할합니다 . 각 호출에 추가되며 각 라인에서 실행될 스크립트입니다.-F
=
@F
-l
\n
print
-e
$F[1]=~s/[^0-9]//g;
: 두 번째 필드에서 숫자가 아닌 문자를 모두 제거합니다($F[1]
두 번째 필드와 마찬가지로 배열은 0부터 계산되기 시작합니다).push @h,$F[0]; push @l,$F[1];
: 첫 번째 필드를 배열에 추가@h
하고 두 번째 필드(이제 숫자가 아닌 필드는 제거됨)를 배열에 추가합니다@l
.END{}
: 입력 파일 전체를 처리한 후 한 번 실행합니다.print join ",",@h;
:@h
배열을 연결하여,
인쇄합니다.print join ",",@l
: 위와 같지만@l
.
답변4
나는 이 질문에 이미 답변되었다는 것을 알고 있습니다. (추악한) bash에서 이것을 달성하는 방법에 대해 2센트만 추가하겠다고 생각했습니다.
최종 결과
echo -e $(cut -d"=" -f1 OpenSimStats.txt | tr '\n' ',' | sed 's/,$/\\n/')$(sed -r 's/.*=([0-9]*).*/\1,/g' OpenSimStats.txt | tr -d '\n' | sed 's/,$//')
그러면 한 줄에 요청한 다음 결과가 생성됩니다.
TestreportsRootAgentCount,TestreportsChildAgentCount,TestreportsGCReportedMemory,TestreportsTotalObjectsCount,TestreportsTotalPhysicsFrameTime,TestreportsPhysicsUpdateFrameTime,TestreportsPrivateWorkingSetMemory,TestreportsTotalThreads,TestreportsTotalFrameTime,TestreportsTotalEventFrameTime,TestreportsLandFrameTime,TestreportsLastCompletedFrameAt,TestreportsTimeDilationMonitor,TestreportsSimFPSMonitor,TestreportsPhysicsFPSMonitor,TestreportsAgentUpdatesPerSecondMonitor,TestreportsActiveObjectCountMonitor,TestreportsActiveScriptsMonitor,TestreportsScriptEventsPerSecondMonitor,TestreportsInPacketsPerSecondMonitor,TestreportsOutPacketsPerSecondMonitor,TestreportsUnackedBytesMonitor,TestreportsPendingDownloadsMonitor,TestreportsPendingUploadsMonitor,TestreportsTotalFrameTimeMonitor,TestreportsNetFrameTimeMonitor,TestreportsPhysicsFrameTimeMonitor,TestreportsSimulationFrameTimeMonitor,TestreportsAgentFrameTimeMonitor,TestreportsImagesFrameTimeMonitor,TestreportsSpareFrameTimeMonitor,TestreportsLastReportedObjectUpdates,TestreportsSlowFrames
0,0,10,0,0,0,2144,0,89,0,0,25,1,55,55,0,0,0,0,0,0,0,0,0,18,0,0,0,0,0,18,0,1
코드 분해
무슨 일이 일어났는지에 대한 자세한 내용은 다음과 같습니다.
외부 에코
echo -e $()$()
-e
인쇄된 결과가 \n
최종 결과에서 줄 바꿈으로 변환되도록 먼저 실행된 두 중첩 명령의 결과를 에코합니다 .
첫 번째 명령
cut -d"=" -f1 OpenSimStats.txt | tr '\n' ',' | sed 's/,$/\\n/'
첫 번째 중첩 명령입니다. =
모든 텍스트를 하나의 열(일련의 \n
구분된 값) 로 추출하기 위한 구분 기호 로 사용됩니다 . 모두를 \n
다음으로 바꾸고 ,
마지막 쉼표를 a로 다시 바꿉니다 \n
(그렇지 않으면 마지막 값 뒤에 쉼표가 옵니다).
명령 자체는 다음과 같은 출력을 생성합니다.
TestreportsRootAgentCount,TestreportsChildAgentCount,TestreportsGCReportedMemory,TestreportsTotalObjectsCount,TestreportsTotalPhysicsFrameTime,TestreportsPhysicsUpdateFrameTime,TestreportsPrivateWorkingSetMemory,TestreportsTotalThreads,TestreportsTotalFrameTime,TestreportsTotalEventFrameTime,TestreportsLandFrameTime,TestreportsLastCompletedFrameAt,TestreportsTimeDilationMonitor,TestreportsSimFPSMonitor,TestreportsPhysicsFPSMonitor,TestreportsAgentUpdatesPerSecondMonitor,TestreportsActiveObjectCountMonitor,TestreportsActiveScriptsMonitor,TestreportsScriptEventsPerSecondMonitor,TestreportsInPacketsPerSecondMonitor,TestreportsOutPacketsPerSecondMonitor,TestreportsUnackedBytesMonitor,TestreportsPendingDownloadsMonitor,TestreportsPendingUploadsMonitor,TestreportsTotalFrameTimeMonitor,TestreportsNetFrameTimeMonitor,TestreportsPhysicsFrameTimeMonitor,TestreportsSimulationFrameTimeMonitor,TestreportsAgentFrameTimeMonitor,TestreportsImagesFrameTimeMonitor,TestreportsSpareFrameTimeMonitor,TestreportsLastReportedObjectUpdates,TestreportsSlowFrames
두 번째 순서
sed -r 's/.*=([0-9]*).*/\1,/g' OpenSimStats.txt | tr -d '\n' | sed 's/,$//'
두 번째 중첩 명령입니다. 각 줄에서 원하는 숫자 주위의 모든 텍스트를 제거하면 숫자 열이 생성됩니다( \n
--구분된 값). 모두를 \n
로 바꾸고 ,
끝에 있는 쉼표를 제거합니다.
결과는 다음과 같습니다.
0,0,10,0,0,0,2144,0,89,0,0,25,1,55,55,0,0,0,0,0,0,0,0,0,18,0,0,0,0,0,18,0,1
상단의 단일 행은 이 세 부분을 하나의 행으로 결합하여 최종 결과를 생성합니다.