You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在for循环中使用grep提取特定行时如何保留换行格式

多文件提取指定行时换行丢失的解决办法

需要从多个文件中提取带行号的行,满足两个条件:

  • 行内容包含ClNonZ
  • 第二个字段为REAL

示例文件内容

foo1.txt

A TEST 0.959660297 0 0.021231423 -0.0073 -0.0031 MhZisp
B REAL 0.180467091 0.800424628 0 0.0566 0.0103 ClNonZ
C REAL 0.98089172 0 0 -0.0158 0.0124 MhNonZ
D TEST 0.704883227 0.265392781 0.010615711 -0.0087 -0.0092 MhZisp
E REAL 0.010615711 0.959660297 0.010615711 0.0476 0.0061 ClNonZ
F TEST 0.704883227 0.265392781 0.010458211 0.0865 0.0548 ClNonZ

foo2.txt

A TEST 0.715498938 0 0.265392781 -0.0013 -0.0309 Unkn
B REAL 0.927813163 0 0.053078556 -0.0051 -0.0636 MhZisp
C TEST 0.55626327 0.222929936 0.201698514 0.0053 -0.0438 MhZisp
D REAL 0.492569002 0.350318471 0.138004246 0.0485 0.0088 ClNonZ
E REAL 0.704883227 0.265392781 0.010615711 0.0476 0.0061 AbbbbZ
F REAL 0.180467091 0.800424628 0 0.0566    0.0103  ClNonZ

单个文件处理(结果正常换行)

直接对单个文件执行命令,结果会正常换行显示:

$ grep -n ClNonZ foo1.txt  | awk '$2 == "REAL" {print $0}'

2:B REAL 0.180467091 0.800424628 0 0.0566 0.0103 ClNonZ
5:E REAL 0.010615711 0.959660297 0.010615711 0.0476 0.0061 ClNonZ

使用for循环处理(换行丢失)

用for循环遍历文件时,把命令结果赋值给变量后再输出,会导致换行丢失,所有匹配行挤在一行:

$ for file in `ls foo*` ; do line=`grep -n ClNonZ $file | awk '$2 == "REAL" {print $0}' `; if [[ -n "$line" ]]; then  echo $file ; echo $line ; echo " " ; fi ; done

foo1.txt
2:B REAL 0.180467091 0.800424628 0 0.0566 0.0103 ClNonZ 5:E REAL 0.010615711 0.959660297 0.010615711 0.0476 0.0061 ClNonZ
 
foo2.txt
4:D REAL 0.492569002 0.350318471 0.138004246 0.0485 0.0088 ClNonZ 6:F REAL 0.180467091 0.800424628 0 0.0566 0.0103 ClNonZ

解决方法

方法1:修正变量赋值后的输出

问题根源是bash在把命令结果赋值给变量时,会将换行符替换成空格。只要在输出变量时用双引号包裹,就能保留换行:

for file in foo*; do
    line=$(grep -n ClNonZ "$file" | awk '$2 == "REAL"')
    if [[ -n "$line" ]]; then
        echo "$file"
        echo "$line"
        echo " "
    fi
done

方法2:改用while循环遍历文件

如果想用while循环,正确的写法如下,避免ls的输出问题,同时保留换行:

printf "%s\n" foo* | while read -r file; do
    line=$(grep -n ClNonZ "$file" | awk '$2 == "REAL"')
    if [[ -n "$line" ]]; then
        echo "$file"
        echo "$line"
        echo " "
    fi
done

方法3:用awk一次性处理所有文件(最优解)

不需要写循环,直接用awk处理所有目标文件,同时满足两个条件,还能自动处理换行和文件名:

awk '
/ClNonZ/ && $2 == "REAL" {
    if (CURRENT_FILE != FILENAME) {
        print FILENAME
        CURRENT_FILE = FILENAME
    }
    print NR ":" $0
    print ""
}
' foo*

执行后会输出和单个文件处理一致的换行格式,同时自动遍历所有foo*文件。


内容的提问来源于stack exchange,提问作者anton

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 03:45:38