代码之家  ›  专栏  ›  技术社区  ›  Martin

Bash:“nl”:去除每个行号前多余空格的最佳方法是什么?

  •  0
  • Martin  · 技术社区  · 4 年前

    我有这个代码:

    sourceStr="abc
    efg
    jkm
    lmn
    efg
    jkm
    lmn
    efg
    jkm
    lmn
    efg
    jkm
    lmn";
    nl -s ". " <<< "$sourceStr"
    

    输出为:

         1. abc
         2. efg
         3. jkm
         4. lmn
         5. efg
         6. jkm
         7. lmn
         8. efg
         9. jkm
        10. lmn
        11. efg
        12. jkm
        13. lmn
    

    我想去掉行号前的空格。“多行RegEx搜索并替换输出”是标准的方法,还是有更好的方法,例如编辑 nl 命令,更改其输出以不包括额外的空格?

    1 回复  |  直到 3 年前
        1
  •  1
  •   shrewmouse    4 年前

    使用sed。

    #!/bin/bash
    
    sourceStr="abc
    efg
    jkm
    lmn
    efg
    jkm
    lmn
    efg
    jkm
    lmn
    efg
    jkm
    lmn";
    
    
    nl -s ". " <<< "$sourceStr" | sed 's/^ *//g'
    

    输出:

    Chris@DESKTOP-BCMC1RF ~
    $ ./test.sh
    1. abc
    2. efg
    3. jkm
    4. lmn
    5. efg
    6. jkm
    7. lmn
    8. efg
    9. jkm
    10. lmn
    11. efg
    12. jkm
    13. lmn
    
        2
  •  1
  •   Nic3500 tpdi    4 年前

    有很多方法可以做到这一点。一、使用 tr .

    #!/bin/bash
    
    sourceStr="abc
    efg
    jkm
    lmn
    efg
    jkm
    lmn
    efg
    jkm
    lmn
    efg
    jkm
    lmn"
    nl -s ". " <<< "$sourceStr" | tr -d ' '
    

    但这将删除所有空格,而不仅仅是前缀。像这样:

    ./so.bash
    1.abc
    2.efg
    3.jkm
    4.lmn
    5.efg
    6.jkm
    7.lmn
    8.efg
    9.jkm
    10.lmn
    11.efg
    12.jkm
    13.lmn
    

    要仅删除前缀,请替换 nl 行与:

    nl -s ". " <<< "$sourceStr" | sed "s#^[ \t]*\(\..*\)*#\1#"
    
    • ^ :以开头
    • [ \t]* :任意数量的空格或制表符
    • \(\..*\) : \. 是数字后面的点。 .* 匹配其他一切。 \( \) 将它们组合在一起
    • \1 :替换为用以下定义的组 \( \) .

    现在的输出是:

    ./so.bash 
    1. abc
    2. efg
    3. jkm
    4. lmn
    5. efg
    6. jkm
    7. lmn
    8. efg
    9. jkm
    10. lmn
    11. efg
    12. jkm
    13. lmn
    
        3
  •  1
  •   xdhmoore    4 年前

    与其他一些解决方案相比,我下面的解决方案的优点是它们使 . 而不会在左侧添加多余的填充。即:

     1. abc
     2. efg
     3. jkm
     4. lmn
     5. efg
     6. jkm
     7. lmn
     8. efg
     9. jkm
    10. lmn
    11. efg
    12. jkm
    13. lmn
    

    关键是,为了获得最小且对齐的缩进,您必须知道行号本身将采用的最大宽度。以下是解决方案 awk 或与 nl + colrm :

    awk解决方案:

    这只是用awk而不是nl对所有行进行编号:

    sourceStr="abc
    efg
    jkm
    lmn
    efg
    jkm
    lmn
    efg
    jkm
    lmn
    efg
    jkm
    lmn";
    
    # Count the number of lines
    total=$(wc -l <<<"$sourceStr")
    
    # Pass the total into awk, using a HERE document for the awk code
    awk -v total=$total -f <(cat <<'HERE'
      BEGIN{
        # Calculate the width of the largest line number
        # using log10(lineNum). Because log in awk is natural log,
        # log10(x) = log(x) / log(10)
        maxWidth=int(log(total)/log(10))
      }
    
      {
        # Calculate the width of the current line number + 1
        n=(int(log(NR)/log(10)) + 1);
        # Print spaces so that the indentation for all line numbers
        # is the same
        for(i=0;i<=maxWidth-n;i++){
          # Use printf because it doesn't print a newline
          printf " "
        }
          # Print the line number and content
          print NR ". " $0
      }
    
    # End the HERE document
    HERE
    ) <<< "$sourceStr"
    

    这给出了上面的结果。

    nl和colrm的解决方案:

    这是最后一行 nl 输出以计算使用删除多少额外缩进 滤掉指定的列 .

    sourceStr="abc
    efg
    jkm
    lmn
    efg
    jkm
    lmn
    efg
    jkm
    lmn
    efg
    jkm
    lmn";
    
    # Add line numbers
    results="$(nl -s '. ' <<< "$sourceStr")"
    
    # Count the number of spaces at the beginning of the last line
    # 1) use tail to get the last line
    # 2) use sed to remove everything except the starting spaces
    # 3) use wc to count the spaces
    indent=$(("$(tail -n1 <<< "$results" | sed -E 's/^( *).*/\1/g' | wc -m)" - 1))
    
    # Remove the first X spaces from all the lines
    colrm 1 $indent <<< "$results"
    

    这给出了相同的结果。

        4
  •  0
  •   ctac_    4 年前

    你可以用列来尝试这种方式

    nl -s ". " <<< "$sourceStr" | column -o " " -R 1 -t
    

    列右侧的选项-R 1将第一列中的数字对齐。

    来自util-linux2.36.1的列

        5
  •  0
  •   ouflak    3 年前

    man nl列出了宽度标志。

    -w、 --数字宽度=数字 使用NUMBER列表示行号

    所以试试:

    nl -w1 -s". " <<< "$sourceStr"
    

    输出:

    1. abc
    2. efg
    3. jkm
    4. lmn
    5. efg
    6. jkm
    7. lmn
    8. efg
    9. jkm
    10. lmn
    11. efg
    12. jkm
    13. lmn
    
        6
  •  0
  •   RARE Kpop Manifesto    2 年前

    使用1个单曲 awk 做这一切可能会一团糟。以链式方式进行操作要简单得多:

     jot -s '' -c - 97 122 | mawk 'gsub(".",$_,$_) + \
                                  gsub(".",$_,$_) +   \
                                 gsub(".","&\n")' FS='^$' RS= | shuf |
    

    mawk '$!NF = substr(_="", gsub("...", "\n\t  " (\
                 substr("__________", ++_, int(length($!_++)/++_)))"= &", 
         $!(NF = NF))) $!_' RS= OFS= FS='\n'                |
    
    mawk -F'^$' 'sub("  [_]+=", sprintf("%#\0478.f", NR))_' | 
    

    --需要筛选的行太多

    mawk -F'^$' -Wi '_<(_+=(_==NR)*__)' \_=127 __=10987
    

    .

              127. wqy
           11,114. xry
           22,101. ice
           33,088. qog
           44,075. ecl
           55,062. cfv
           66,049. afk
           77,036. zzv
           88,023. huh
           99,010. ujw
          109,997. ojp
          120,984. uxi
          131,971. qri
          142,958. emd
    

    如果左侧空白太大,请提取较短的格式化子字符串

        7
  •  0
  •   ufopilot    2 年前
    $ awk '$0=NR". "$0' <<<"$sourceStr" 
    1. abc
    2. efg
    3. jkm
    4. lmn
    5. efg
    6. jkm
    7. lmn
    8. efg
    9. jkm
    10. lmn
    11. efg
    12. jkm
    13. lmn
    
    $ awk '{printf "%2d. %s\n",NR,$0}' <<<"$sourceStr" 
     1. abc
     2. efg
     3. jkm
     4. lmn
     5. efg
     6. jkm
     7. lmn
     8. efg
     9. jkm
    10. lmn
    11. efg
    12. jkm
    13. lmn