1

テキスト ファイルの内容を行ごと (tac のように) だけでなく、行のグループ (セクション) ごとに反転するエレガントな方法を探しています。次の例は網羅的なものです。

元のファイルの内容:

--------    -----
    time        |
--------        | 
10:00:00        |--- section 1 
10:00:10        | 
10:00:20        |
--------    -----
--------    -----
    time        |
--------        | 
10:01:00        |--- section 2 
10:01:10        | 
10:01:20        |
--------    -----

望ましい出力:

--------    -----
    time        |
--------        | 
10:01:00        |--- section 2 
10:01:10        | 
10:01:20        |
--------    -----
--------    -----
    time        |
--------        | 
10:00:00        |--- section 1 
10:00:10        | 
10:00:20        |
--------    -----
4

4 に答える 4

2

awk でできること:

awk '{a[i++]=$0};/-----/{++j};j==3{t="";for(k=0;k<i;++k)t=t a[k]"\n";b[++l]=t;i=j=0}END{for(i=l;i;--i)printf "%s", b[i]}' file

出力:

----------------------------------------------------------------
date        time        hostname    cpu     ram     /       /opt
----------------------------------------------------------------
2013/09/08  15:40:00    server1     20%     30%     50%     70%
2013/09/08  15:40:00    server2     15%     21%     49%     72%
2013/09/08  15:40:00    server3     20%     40%     40%     75%
----------------------------------------------------------------
----------------------------------------------------------------
date        time        hostname    cpu     ram     /       /opt
----------------------------------------------------------------
2013/09/08  15:35:00    server1     15%     30%     50%     70%
2013/09/08  15:35:00    server2     18%     21%     49%     72%
2013/09/08  15:35:00    server3     15%     40%     40%     75%
----------------------------------------------------------------
----------------------------------------------------------------
date        time        hostname    cpu     ram     /       /opt
----------------------------------------------------------------
2013/09/08  15:30:00    server1     20%     30%     50%     70%
2013/09/08  15:30:00    server2     10%     21%     49%     72%
2013/09/08  15:30:00    server3     15%     40%     40%     75%
----------------------------------------------------------------

無効なデータを除外できる別のより安全なバリエーション:

awk '/^-----+$/{++j};!j{next};{a[i++]=$0}j==3{t="";for(k=0;k<i;++k)t=t a[k]"\n";b[++l]=t;i=j=0}END{for(i=l;i;--i)printf "%s", b[i]}' file

行数に基づく別のもの:

awk '{a[i++]=$0}i==7{t="";for(k=0;k<i;++k)t=t a[k]"\n";b[++l]=t;i=0}END{for(i=l;i;--i)printf "%s", b[i]}' file

もう少し簡単:

awk '{a[i++]=$0}i==7{t="";for(i=0;i<7;++i)t=t a[i]"\n";b[++j]=t;i=0}END{for(;j;--j)printf "%s", b[j]}' file

同じコンセプトでBashでそれを行う別の簡単な方法:

( IFS=$'\n'; while read -r A[I++]; do [[ I -eq 7 ]] && { B[++J]="${A[*]}"; I=0; }; done; for ((;J;--J)); do echo "${B[J]}"; done; ) < file

Rubyのもう1 つの真のワンライナー:

ruby -e '$stdin.readlines().each_slice(7).entries.reverse.each { |b| puts b; }' < file
于 2013-09-08T13:50:12.337 に答える
0

これは私のbashソリューションです

tmparr=()
blockSize=7
i=$blockSize
tac file | while read line; do  
tmparr[$i]="$line" && ((i--))  
[ $i -eq 0 ] && i=$blockSize && for j in "${tmparr[@]}"; do echo "$j"; done
done
于 2013-09-16T01:49:19.330 に答える
0

awk間違いなく正しい方法ですが、ここに bash の代替手段があります。

#!/bin/bash

separator='----------------------------------------------------------------' # each block must end with a separator
blockSeparators=3 # number of separators in each block. Could be 1 as well

dataArr=()
current=0
subCounter=0
while read -r curLine; do
    dataArr[current]+=$curLine$'\n'
    if [[ $curLine == "$separator" ]]; then
        (( ++subCounter == blockSeparators )) && (( current++ , subCounter=0 ))
    fi
done < file.txt

for (( i=${#dataArr[@]}; i>=0; i-- )); do
    echo -n "${dataArr[i]}"
done

そして、すべてのブロックが正確に 7 行であることがわかっている場合:

#!/bin/bash

blockLines=7

dataArr=()
current=0
lineCounter=0
while read -r curLine; do
    dataArr[current]+=$curLine$'\n'
    (( ++lineCounter == blockLines )) && (( current++ , lineCounter=0 ))
done < file.txt

for (( i=${#dataArr[@]}; i>=0; i-- )); do
    echo -n "${dataArr[i]}"
done

しかし、すでに述べたように、awkソリューションを使用してください。Bash はそのような操作を行うのに適切ではありません :)

編集:

bash ではさらに短くなります。

blockSize=7

readarray lines < file.txt
for (( i=${#lines[@]}-blockSize; i>=0; i-=blockSize )); do
    ( IFS=''; echo -n "${lines[*]:i:blockSize}" )
done
于 2013-09-08T14:08:26.443 に答える