首頁  >  問答  >  主體

linux - shell怎么多行并作一行处理?

如果第1行和第2行都不以;开头,则合并这两行为新行,并继续处理新行和第3行;
如果第1行以;开头,则继续处理第2行和第3行。
以上流程仅为方便描述,只要能达到相同效果即可。
如输入为:
;a
;;b
c
d;
e;;;
;f
g
期望输出:
;a
;;b
cd;e;;;
;f
g

PHPzPHPz2742 天前816

全部回覆(4)我來回復

  • 大家讲道理

    大家讲道理2017-04-17 12:07:30

    答案

    awk '!/^;/{a=arrreee}/^;/{if(a!="")print a;print rrreee;a="";}END{if(a!="")print a;}'
    

    解釋

    awk語法 test1{statements1}test2{statements2}...

    針對每一行,若符合test1,則執行statement1,若滿足test2,執行statement2 ...

    所以分3部分:

    • !/^;/{a=a;} 如果不以a開頭,則將目前行追加到臨時變數
      (作為緩衝區)
      • !/^;/

        • !
        • 否定
        • /.../
        • 表示測試目前行是否滿足給定正規表示式
        • ^; ; 正規表示式,表示以
        • 開頭
      • a=a

        • a
        • 變量,無聲明,直接使用,預設值是0、null、"",根據使用場景自動轉換,這裡第一次用就是空字串
        • a
        • 表示整個一行的內容
      兩個字串寫在一起,表示字串拼接
    • /^;/{if(a!="")print a;print ;;a="";} a

        若以
      • 開頭,先輸出暫時拼接的變數/^;/(若有),再輸出目前行;
      • if(a!="")print a;print
        ;a="";

        判斷目前行是否以
          開頭
        • if(a!="")print a;
        • print
        • ;
        • a=""; a 如果a不為空,則輸出a的值(print自動換行)
      • 列印目前行
    • 清空END{if(a!="")print a;}的值,以備下次使用a

      • ; a 處理完所有行,最後再判斷緩衝區;中是否有內容,若有,則列印
      • END BEGIN如果最後幾行都不以
      • 開頭,會全部追加到
      中,一直沒有機會輸出出來,因為碰到
    • 開頭的行才會輸出
    <🎜> <🎜>條件表示處理完最後一行之後(相對的當然有<🎜>,表示處理第一行之前)<🎜> <🎜> <🎜> <🎜>

    回覆
    0
  • PHP中文网

    PHP中文网2017-04-17 12:07:30

    首先: 將換行符號去掉,/n//g
    然後: 判斷字母序列右邊是否有數字,有則在右邊加上換行符/([a-z]+)(?=[0-9]+)/1/n/g
    判斷字母序列左側是否有數字,有則在左側加上換行符/([a-z]+)(?<=[0-9]+)//n1/g
    最後: 將上面正規表示式用sedawk實現。

    回覆
    0
  • 天蓬老师

    天蓬老师2017-04-17 12:07:30

    awk版本

    awk '
    sed -n '/^;/{H;x;s/^\n//g;p;s/.*//g;x;};/^;/!{H;x;s/\n//g;x};${/^;/!p}' urfile
    
    !~ /^;/{a=arrreee;}/^;/{print a?a"\n"rrreee:rrreee;a=""}END{if(a)print a}' urfile

    再附加一個sed的

    rrreee

    回覆
    0
  • PHPz

    PHPz2017-04-17 12:07:30

    這種略複雜的需求,用sed/awk是可以實現,但是我覺得不推薦,這時候一般用python或perl來做更有效率。

    不過為了看看我的sed功底還在不在,還是試了一下,目前簡單測試沒有發現問題,程式碼如下:

    sed -r -n '/^;/!{h;s/.*//;x;:l $!{H;n;/^;/!b l};x;s/\n//gp;g};p'
    

    解釋幾個重點的部分:
    1. h;s/.*//;x;是為了清空hold space
    2. :l $!{H;n;/^;/!b l};部分是一個循環,將所有的非;開頭的行合併到hold space,退出條件有兩個:到達最後一行或遇到一個;開頭的行
    3. x;s/n//gp;g 將hold space中的內容去掉換行符並列印出來
    4. 最後p列印pattern space中的內容,用來列印;開頭的行

    答案還沒寫完,發現一個bug了: 如果檔案的最後有2行以上的非;開頭的行,最後一行沒有被合併。

    修改一下原來的答案為:

    sed -r -n '/^;/!{h;s/.*//;x;:l $!{H;n;/^;/!b l};/^;/!{H;g;s/\n//gp;t};x;s/\n//gp;g};p'
    

    修改說明:
    1. 跳出迴圈之後,判斷目前行如果不是;開頭(根據先前的跳出條件可知,這是最後一行),將目前行加入hold space,然後處理hold space的內容

    看吧,一個其實也不是很複雜的需求,用sed來寫,命令越寫越長,1個月後還能一眼看懂麼?這類需求還是不要用sed來做吧

    回覆
    0
  • 取消回覆