web-dev-qa-db-ja.com

ファイルの最も長い行を印刷する方法は?

ファイルの最も長い行を印刷する最も簡単な方法を探しています。私はいくつかグーグルをしました、そして驚くべきことに答えを見つけることができなかったようです。ファイル内の最も長い行の長さを頻繁に印刷しますが、実際に最も長い行を印刷する方法がわかりません。誰かがファイルの最も長い行を印刷するソリューションを提供できますか?前もって感謝します。

37
dr.bunsen
cat ./text | awk ' { if ( length > x ) { x = length; y = $0 } }END{ print y }'

[〜#〜] upd [〜#〜]:コメント内のすべてのアドバイスの要約

awk 'length > max_length { max_length = length; longest_line = $0 } END { print longest_line }' ./text 
cat filename | awk '{ print length }' | sort -n | tail -1
7
aspinalln

最長の最初の行をグレップ

_grep -Em1 "^.{$(wc -L <file.txt)}\$" file.txt 
_

このコマンドは、Shell-構文とregexp構文が混在しているため、実際に読むことは非常に困難です。
説明のために、最初に簡略化された疑似コードを使用します。 _##_で始まる行は、シェルでは実行されません。
この簡略化されたコードはファイル名Fを使用し、読みやすくするために引用符と正規表現の一部を省略しています。

使い方

コマンドには、grep-とwcの2つの部分があります。

## grep "^.{$( wc -L F )}$" F

wcはプロセス拡張$( ... )で使用されるため、grepの前に実行されます。最も長い線の長さを計算します。シェル拡張構文は、混乱する方法で正規表現パターン構文と混合されているので、プロセス拡張を分解します。

_## wc -L F_
_42_
_## grep "^.{42}$" F_

ここでは、プロセス展開がそれが返す値で置き換えられ、使用されるgrepコマンドラインが作成されました。これで、正規表現をより簡単に読み取ることができます。これは、行の開始(_^_)から終了(_$_)まで正確に一致します。それらの間の式は、改行以外の任意の文字に一致し、42回繰り返されます。結合すると、正確に42文字で構成される行になります。


次に、実際のシェルコマンドに戻ります。grepオプション_-E_(_--extended-regexp_)は、読みやすくするために_{}_をエスケープしないようにします。オプション_-m 1_(_--max-count=1_)は、最初の行が見つかった後に停止します。 wcコマンドの_<_は、wcがファイル名と長さを一緒に出力しないように、ファイルをその標準入力に書き込みます。

一番長い路線は?

ファイル名が2回出現する例を読みやすくするために、ファイル名に変数fを使用します。例の各_$f_は、ファイル名で置き換えることができます。

_f="file.txt"
_

最初の最長行-最初の行を最長行と同じ長さで表示します。

_grep -E -m1 "^.{$(wc -L <"$f")}\$" "$f"
_

表示すべての最長行-最長の行と同じ長さのすべての行:

_grep -E "^.{$(wc -L <"$f")}\$" "$f" 
_

最後の最長行-最後の行と同じ長さの最後の行を表示します。

_tac "$f" | grep -E -m1 "^.{$(wc -L <"$f")}\$"
_

単一の最長行-他のすべての行よりも長い最長の行を表示するか、失敗します。

_[ $(grep -E "^.{$(wc -L <"$f")}\$" "$f" | wc -l) = 1 ] && grep -E "^.{$(wc -L <"$f")}\$" "$f" 
_

(最後のコマンドは、完全なgrepコマンドを繰り返すため、他のコマンドよりもさらに非効率的です。wcの出力とgrepによって書き込まれた行が次の場所に保存されるように分解する必要があります。変数。
最も長い行はすべて実際にはすべての行である可能性があることに注意してください。変数に保存するには、最初の2行だけを保持する必要があります。)

5
Volker Siegel
sed -rn "/.{$(<file expand -t1 |wc -L)}/{p;q}" file

これは最初にコマンド置換内のファイルを読み取り、最長の行の長さを出力します(以前は、expandはタブをスペースに変換して、wc -Lのセマンティクスを克服します-行の各タブは1の代わりに8を行の長さに追加します)。この長さはsed式で使用され、「この文字数の行を1行検索して出力し、終了する」ことを意味します。したがって、これは実際には、最長の行がファイルの先頭に近いほど最適である可能性があります(素晴らしい、建設的なコメントをありがとう)。

もう1つ、私は(bashで)sedのものより前に考えていました:

#!/bin/bash
while read -r line; do
    (( ${#line} > max )) && max=${#line} && longest="$line"
done
echo "$longest"
5
ata

これがPerlソリューションです:

Perl -e 'while(<>){
           $l=length;  
           $l>$m && do {$c=$_; $m=$l}  
         } print $c' file.txt 

または、印刷したい場合all最も長い行

Perl -e 'while(<>){
           $l=length;
           Push @{$k{$l}},$_;
           $m=$l if $l>$m;
         } print @{$k{$m}}' file.txt 

何もすることがないので、625Mのテキストファイルでいくつかのベンチマークを実行しました。驚いたことに、私のPerlソリューションは他のソリューションよりも一貫して高速でした。確かに、受け入れられたawkソリューションとの違いはわずかですが、それはあります。明らかに、複数の行を印刷するソリューションの方が遅いので、タイプ別にソートしました。

最も長い行の1つだけを印刷します。

$ time Perl -e 'while(<>){
           $l=length;  
           $l>$m && do {$c=$_; $m=$l}  
         } print $c' file.txt 
real    0m3.837s
user    0m3.724s
sys     0m0.096s



$ time awk 'length > max_length { max_length = length; longest_line = $0 }
 END { print longest_line }' file.txt
real    0m5.835s
user    0m5.604s
sys     0m0.204s



$ time sed -rn "/.{$(<file.txt expand -t1 |wc -L)}/{p;q}" file.txt 
real    2m37.348s
user    2m39.990s
sys     0m1.868s

最も長い行をすべて印刷します。

$ time Perl -e 'while(<>){
           $l=length;
           Push @{$k{$l}},$_;
           $m=$l if $l>$m;
         } print @{$k{$m}}' file.txt 
real    0m9.263s
user    0m8.417s
sys     0m0.760s


$ time awk 'length >x { delete y; x=length }
     length==x { y[NR]=$0 } END{ for (z in y) print y[z] }' file.txt
real    0m10.220s
user    0m9.925s
sys     0m0.252s


## This is Chris Down's bash solution
$ time ./a.sh < file.txt 
Max line length: 254
Lines matched with that length: 2
real    8m36.975s
user    8m17.495s
sys     0m17.153s
4
terdon

次の例はdmitry.malikov's回答に対するコメントでしたが、そうであったはずですが、Visible Comment Spaceの無用な使用があるため、ここにそれを提示することを選択しました、少なくともそれは見られます...

これはdmitry'sシングルパスawkメソッドの単純なバリエーションです。
すべての「等しい最長」の行を印刷します。 (注意。 delete arrayはgawkの拡張機能です)。

awk 'length >x { delete y; x=length }
     length==x { y[NR]=$0 } END{ for (z in y) print y[z] }' file
2
Peter.O

純粋なbashでは:

#!/bin/bash

_max_length=0
while IFS= read -r _line; do
    _length="${#_line}"
    if (( _length > _max_length )); then
        _max_length=${_length}
        _max_line=( "${_line}" )
    Elif (( _length == _max_length )); then
        _max_line+=( "${_line}" )
    fi
done

printf 'Max line length: %d\n' "${_max_length}"
printf 'Lines matched with that length: %d\n' "${#_max_line[@]}"
(( ${#_max_line[@]} )) && printf '%s\n' '----------------' "${_max_line[@]}"
1
Chris Down

このための小さなシェルスクリプトを開発しました。長さ、行番号、および行自体を、80文字のような特定のサイズを超える長さで表示します。

#!/bin/sh

# Author: Surinder

if test $# -lt 2
then
   echo "usage: $0 length file1 file2 ..."
   echo "usage: $0 80 hello.c"
   exit 1
fi

length=$1

shift

LONGLINE=/tmp/longest-line-$$.awk

cat << EOF > $LONGLINE
  BEGIN {
  }

  /.*/ {
    current_length=length(\$0);
    if (current_length >= expected_length) {
       printf("%d at line # %d %s\n", current_length, NR, \$0);
    }
  }

  END {
  }
EOF

for file in $*
do
  echo "$file"
  cat $file | awk -v expected_length=$length -f $LONGLINE |sort -nr
done

rm $LONGLINE

https://github.com/lordofrain/tools/blob/master/longest-line/longest-line.sh

0
Surinder432