공백이 있으면 제거하고 없으면 무시하십시오.

공백이 있으면 제거하고 없으면 무시하십시오.

프로그램 출력에서 ​​.csv 파일을 만들고 싶습니다. 원본 출력 중 일부를 이 수준으로 사용자 정의했습니다.

  36.343074719185125    -1.488697037254009     0.517768286726280  -1.488697037254009    48.906350248447872    -0.255764113311881   0.51776828
6726280    -0.255764113311881    31.687963239227631

지금까지 나는 이러한 명령을 사용해 왔습니다.

tail -12 Q.out | head -3 | sed 's/^........//' | tr -d '\n' > q.txt

문제는 그 사이에 특정한 수의 공백이 없다는 것입니다. 4개일 때도 있고 3개일 때도 있습니다. 그것은 모두 프로그램의 출력에 달려 있습니다. 예를 들어 첫 번째 값이 36.343이면 공백 2개, 3.6이면 공백 3개, 360.34이면 공백 1개 앞에 붙습니다. 좀 더 깔끔하게 만드는 방법은 없을까요?

원시 데이터


                   0                     1                     2        

    0     36.343074719185125    -1.488697037254009     0.517768286726280
    1     -1.488697037254009    48.906350248447872    -0.255764113311881
    2      0.517768286726280    -0.255764113311881    31.687963239227631

    alpha_(0.000) =      38.979129402287 a.u.
FCHKWriter: !WARNING! method 'CCSD'' renamed to label 'CC'.
FCHKWriter: Writing 0100-A_ccsd.fchk with label ' CC Density'.

    Psi4 stopped on: Tuesday, 12 October 2021 04:09PM
    Psi4 wall time for execution: 0:17:43.19

*** Psi4 exiting successfully. Buy a developer a beer!

예상되는 결과

36.343074719185125,-1.488697037254009,0.517768286726280,-1.488697037254009,48.906350248447872,-0.255764113311881,0.51776828
6726280,-0.255764113311881,31.687963239227631

우분투 20.04를 사용하고 있습니다

답변1

우리가 관심 있는 데이터의 세 행이 원본 데이터의 행 4, 5, 6이고 이 모든 숫자를 쉼표로 구분된 목록으로 한 줄에 입력한다고 가정해 보겠습니다.

다음 표현식은 sed원하는 행 범위 내에 있지 않은 모든 행을 삭제한 다음 숫자만 포함하는 첫 번째 열을 삭제합니다. 이 tr명령은 이 데이터를 읽고 데이터를 한 줄에 하나씩 숫자 목록으로 변환합니다. 줄 바꿈으로 구분된 숫자는 쉼표로 구분된 목록으로 변환됩니다 paste.

sed -e '4,6 !d' \
    -e 's/[[:blank:]]*[[:digit:]]*[[:blank:]]*//' file |
tr -s ' ' '\n' |
paste -s -d, -

trsed반복되는 공백을 단일 쉼표로 바꾸면 이를 제거 할 수 있습니다 .

sed -e '4,6 !d' \
    -e 's/[[:blank:]]*[[:digit:]]*[[:blank:]]*//' \
    -e 's/[[:blank:]]\{1,\}/,/g' file |
paste -s -d, -

답변2

공백으로 구분된 데이터를 처리하는 데 매우 능숙합니다. @they처럼 관심 있는 3개 행이 4,5,6행이라고 가정해 보겠습니다.

awk -v OFS=, '4 <= NR && NR <= 6 {print $2,$3,$4}' Q.out

산출

36.343074719185125,-1.488697037254009,0.517768286726280
-1.488697037254009,48.906350248447872,-0.255764113311881
0.517768286726280,-0.255764113311881,31.687963239227631

그런 다음 이를 행으로 연결하려면 다음을 사용하십시오.paste

awk -v OFS=, '4 <= NR && NR <= 6 {print $2,$3,$4}' Q.out | paste -sd,

데이터는 다음 위치에 있습니다.마지막파일의 10~12번째 줄. 우리를 보자취소파일을 만들고, 알려진 행 범위에서 데이터를 추출하고, 데이터를 다시 반전하고, 조인합니다.

tac Q.out \
| awk -v OFS=, '10 <= NR && NR <= 12 {print $2,$3,$4}' \
| tac \
| paste -sd,
36.343074719185125,-1.488697037254009,0.517768286726280,-1.488697037254009,48.906350248447872,-0.255764113311881,0.517768286726280,-0.255764113311881,31.687963239227631

답변3

이를 사용하여 awk데이터 파일을 처리할 수 있습니다. 귀하의 예를 보면 각 행에 4개의 필드가 있고 첫 번째 필드는 음수가 아닌 정수라고 가정할 수 있는 것 같습니다.

awk 'NF == 4 && $1 ~ /^[0-9]+$/ {printf "%s,%s,%s\n", $2, $3, $4}' Q.out

결과

36.343074719185125,-1.488697037254009,0.517768286726280
-1.488697037254009,48.906350248447872,-0.255764113311881
0.517768286726280,-0.255764113311881,31.687963239227631

모든 데이터를 한 줄에 표시하고 싶다는 다양한 의견을 보았습니다. 이것은귀하의 질문에 설명이 없습니다, 혼란스러운 두 줄의 불규칙한 출력이 있지만 어쨌든 수정하겠습니다.

여기에서 원래 awk문을 수정하여 후속 데이터 행을 초기 행에 추가한 다음 후행 개행 문자를 추가할 수 있습니다.

awk '
    NF == 4 && $1 ~ /^[0-9]+$/ {printf "%s%s,%s,%s", s, $2, $3, $4; s=","}
    END {print ""}
' Q.out

답변4

모든 Unix 시스템의 모든 쉘에서 awk를 사용하고 CSV로 변환하려는 입력에 다음과 같이 길이가 불확실한 블록이 여러 개 있다고 가정합니다.

$ cat tst.awk
BEGIN { OFS="," }
(NF==4) && sub(/^ +[0-9]+ +/,"") {
    $1 = $1
    rec = (rec == "" ? "" : rec OFS) $0
}
!NF && (rec != "") {
    print rec
    rec = ""
}

$ awk -f tst.awk file
36.343074719185125,-1.488697037254009,0.517768286726280,-1.488697037254009,48.906350248447872,-0.255764113311881,0.517768286726280,-0.255764113311881,31.687963239227631

관련 정보