在一个列bash中替换模式



我有多个*csv文件,我喜欢:

#sample,time,N
SPH-01-HG00186-1_R1_001,8.33386,93
SPH-01-HG00266-1_R1_001,7.41229,93
SPH-01-HG00274-1_R1_001,7.63903,93
SPH-01-HG00276-1_R1_001,7.94798,93
SPH-01-HG00403-1_R1_001,7.99299,93
SPH-01-HG00404-1_R1_001,8.38001,93

我试着把csv文件整理成:

#sample,time,N
HG00186,8.33386,93
HG00266,7.41229,93
HG00274,7.63903,93
HG00276,7.94798,93
HG00403,7.99299,93
HG00404,8.38001,93

我:

for i in $(ls *csv); do line=$(cat ${i} | grep -v "#" | cut -d'-' -f3); sed 's/*${line}*/${line}/g'; done

然而没有结果显示…有什么建议吗?谢谢。

使用awk和用,分割每一行的逻辑,然后用-分割它们的第一个字段:

awk -v FS=',' -v OFS=',' 'NR > 1 { split($1,w,"-"); $1 = w[3] } 1' file.csv

使用sed和不可能修改其他字段的健壮正则表达式:

sed -E 's/^([^,-]*-){2}([^,-]*)[^,]*/2/' file.csv
# or
sed -E 's/^(([^,-]*)-){3}[^,]*/2/' file.csv

使用下面的Perl一行代码:

perl -i -pe 's{.*?-.*?-(.*?)-.*?,}{$1,}' *.csv

Perl单行程序使用这些命令行标志:
-e:告诉Perl查找内联代码,而不是在文件中查找。
-p:每次循环输入一行,默认赋值给$_。在每次循环迭代后添加print $_
-i.bak:就地编辑输入文件(覆盖输入文件)。在覆盖之前,保存原始文件的备份副本,在其名称后面附加扩展名.bak(您可以省略.bak,以避免创建任何备份文件)。

参见:
perldoc perlrun:如何执行Perl解释器:命令行开关
perldoc perlre: Perl正则表达式(regexes)
perldoc perlre: Perl正则表达式(regexes):量词;字符类和其他特殊转义;断言;捕获组
perldoc perlrequick: Perl正则表达式快速入门

可以使用

sed -E 's/^[^-]+-[0-9]+-([^-]+)[^,]+/1/' file > newfile

细节:

  • -E-启用POSIX ERE正则表达式样式
  • ^[^-]+-[0-9]+-([^-]+)[^,]+-搜索的正则表达式模式
    • ^-起始字符串
    • [^-]+-一个或多个非连字符
    • --连字符
    • [0-9]+-一个或多个数字
    • --连字符
    • ([^-]+)-组1:一个或多个非连字符
    • [^,]+-一个或多个非逗号字符
  • 1-将匹配项替换为组1值

查看在线演示:

#!/bin/bash
s='SPH-01-HG00186-1_R1_001,8.33386,93
SPH-01-HG00266-1_R1_001,7.41229,93
SPH-01-HG00274-1_R1_001,7.63903,93
SPH-01-HG00276-1_R1_001,7.94798,93
SPH-01-HG00403-1_R1_001,7.99299,93
SPH-01-HG00404-1_R1_001,8.38001,93'
sed -E 's/^[^-]+-[0-9]+-([^-]+)[^,]+/1/' <<< "$s"

输出:

HG00186,8.33386,93
HG00266,7.41229,93
HG00274,7.63903,93
HG00276,7.94798,93
HG00403,7.99299,93
HG00404,8.38001,93

您可以使用bash参数扩展来修改文本,而无需借助awk和sed等外部工具:

IFS=","
while read -r -a line; do
x="${line[0]%-*}"
x="${x##*-}"
printf "%s,%s,%sn" "$x" "${line[1]}" "${line[2]}"
done < input.txt

或者您可以使用简单的awk,就像其他人所做的那样。

awk '{print $3,$5,$6}' FS='[-,]' OFS=, < input.txt

如果您需要不惜任何代价使用cut,那么我建议以下解决方案,让file.txt内容为

#sample,time,N
SPH-01-HG00186-1_R1_001,8.33386,93
SPH-01-HG00266-1_R1_001,7.41229,93
SPH-01-HG00274-1_R1_001,7.63903,93
SPH-01-HG00276-1_R1_001,7.94798,93
SPH-01-HG00403-1_R1_001,7.99299,93
SPH-01-HG00404-1_R1_001,8.38001,93

然后

head -1 file.txt && tail -6 file.txt | tr '-' ',' | cut --delimiter=',' --fields=3,5,6

给输出

#sample,time,N
HG00186,8.33386,93
HG00266,7.41229,93
HG00274,7.63903,93
HG00276,7.94798,93
HG00403,7.99299,93
HG00404,8.38001,93

解释:输出第一行按原样使用head,然后将最后6行填充到tr中,使用,替换-,最后使用cut,分隔符并指定所需字段。

{m,n,g}awk NF++ FS='^[^-]+-[^-]+-|-[^,]+' OFS=

|

#sample,time,N
HG00186,8.33386,93
HG00266,7.41229,93
HG00274,7.63903,93
HG00276,7.94798,93
HG00403,7.99299,93
HG00404,8.38001,93

相关内容

  • 没有找到相关文章

最新更新