ファイルの最も長い行を印刷する最も簡単な方法を探しています。私はいくつかグーグルをしました、そして驚くべきことに答えを見つけることができなかったようです。ファイル内の最も長い行の長さを頻繁に印刷しますが、実際に最も長い行を印刷する方法がわかりません。誰かがファイルの最も長い行を印刷するソリューションを提供できますか?前もって感謝します。
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
_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行だけを保持する必要があります。)
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"
これが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
次の例は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
純粋な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[@]}"
このための小さなシェルスクリプトを開発しました。長さ、行番号、および行自体を、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