如果有空格则将其删除,如果没有则忽略

如果有空格则将其删除,如果没有则忽略

我想从程序输出创建 .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,则前面有两个空格,如果是3.6,则前面有三个空格,如果是360.34,则前面有一个空格。有什么办法可以让它更干净吗?

原始数据


                   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

我使用的是 UBUNTU 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, -

tr您可以通过sed用单个逗号替换重复的空格来摆脱它。

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处理数据文件。看看你的例子,我似乎可以假设每行有四个字段,第一个字段是非负整数:

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 机器的任何 shell 中使用任何 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

相关内容