답변:
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
)을 호출 하고 파이프를 사용하는 것은 비용이 많이 드는 작업이지만 awk가 파일을 읽는 것이 더 효율적이라는 것은 말할 것도 없습니다. 이 작업을 자주 수행하면 성능에 미치는 영향이 눈에 띄게 나타납니다 cat
.
cat
여기서는 쓸모가 없습니다. 컴퓨터에는 쓸모가 없지만 사람에게는 가치가 있습니다. 첫 번째 변형은 입력을 명확하게 보여줍니다. 흐름이 더 자연 스럽습니다 (왼쪽에서 오른쪽으로). 두 번째 경우에는 창을 스크롤하지 않으면 입력이 무엇인지 알 수 없습니다.
cat
. < file command
잘 작동합니다.
< filename command
와 같습니다 filename < command
. 그러나 일단 알고 있으면 데이터 흐름의 방향을 명확하게 보여주는 긴 파이프를 작성할 때 (추가 명령을 호출하지 않고) 파이프를 활용할 수 있습니다.< input-file command1 | command2 | command3 > output-file
sed -rn "/.{$(<file expand -t1 |wc -L)}/{p;q}" file
먼저 명령 대체 내부의 파일을 읽고 가장 긴 줄의 길이를 출력합니다 (이전 expand
의 의미를 극복하기 위해 탭을 공백으로 변환 함 wc -L
-줄의 각 탭 은 1 에서 줄 길이 대신 8 을 추가합니다 ). 그런 다음이 길이는 sed
"이 문자 수만큼 줄을 찾아서 인쇄 한 다음 종료"를 의미 하는 표현식에 사용됩니다 . 따라서 이것은 가장 긴 줄이 파일의 상단에 가까울수록 최적 일 수 있습니다.
다른 하나는 sed보다 먼저 생각했습니다 (bash).
#!/bin/bash
while read -r line; do
(( ${#line} > max )) && max=${#line} && longest="$line"
done
echo "$longest"
-L, --max-line-length
은 맨 페이지에 따라 가장 긴 줄의 길이를 인쇄하지만, 더 잘못 파고 들거나 ( 예기치 않은 결과가 나올 때와 같이 ),이 옵션은 1 개의 탭 문자 마다 길이가 8 씩 증가합니다. 이 참조 유닉스 및 리눅스 Q / A\x09
sed -rn "/.{$(<file expand -t1 |wc -L)}/p" file
read line
백 슬래시 이스케이프 된 문자를 리터럴 문자로 해석합니다 (예 : \A
resloves to A
). 물론 실제 바이트 사용량보다 짧은 시간을 효과적으로보고합니다.이 이스케이프 된 해석 을 방지하려면 다음을 사용하십시오 read -r line
.. . . . 또한, 만드는 나오지 + 화장실 버전이 첫 번째 "긴 라인"후 종료, 변경 p
에 {p;q}
..sed -rn "/.{$(<file expand -t1 |wc -L)}/{p;q}" file
Perl 솔루션은 다음과 같습니다.
perl -e 'while(<>){
$l=length;
$l>$m && do {$c=$_; $m=$l}
} print $c' file.txt
또는 가장 긴 줄을 모두 인쇄 하려면
perl -e 'while(<>){
$l=length;
push @{$k{$l}},$_;
$m=$l if $l>$m;
} print @{$k{$m}}' file.txt
더 나은 작업이 없었기 때문에 625M 텍스트 파일에서 일부 벤치 마크를 실행했습니다. 놀랍게도 내 Perl 솔루션은 다른 솔루션보다 지속적으로 빠릅니다. 물론 허용되는 awk
솔루션 과의 차이 는 작지만 존재합니다. 분명히 여러 줄을 인쇄하는 솔루션은 느리므로 유형별로 정렬하여 가장 빠르거나 느립니다.
가장 긴 줄 중 하나만 인쇄하십시오.
$ 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
grep -Em1 "^.{$(wc -L <file.txt)}\$" file.txt
이 명령은 쉘 구문과 regexp 구문을 혼합하기 때문에 연습 없이는 읽기가 매우 어렵습니다.
설명을 위해 먼저 단순화 된 의사 코드를 사용합니다. 로 시작하는 행 ##
은 쉘에서 실행되지 않습니다.
이 단순화 된 코드는 파일 이름 F를 사용하고 가독성을 위해 인용 부호와 정규 표현식의 일부를 생략합니다.
이 명령에는 grep
-와 wc
호출의 두 부분이 있습니다 .
## 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
길이와 함께 파일 이름을 인쇄에서.
두 번 나타나는 파일 이름으로 예제를 더 읽기 쉽게하기 위해 파일 이름에 변수 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
이 변수에 저장 되도록 분명히 분해해야 합니다.
가장 긴 행은 실제로 모든 행일 수 있습니다. 변수로 저장하려면 처음 두 줄만 유지하면됩니다.)
순수한 배쉬에서 :
#!/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[@]}"
_max_line[0]=${_line}
은 이전에 누적 된 더 짧은 "가장 긴 줄"을 제거하지 않습니다 ... unset _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
$*
거의 좋은 생각입니다, 당신이 원하는"$@"
. /.*/
당신의는 awk
그뿐만 아니라 빈 줄과 일치하기 때문에 아무것도하지 않습니다. \$0
작은 따옴표를 사용하면 이스케이프를 피할 수 있습니다 'EOF'
. 왜 빈 BEGIN{}
블록을 사용합니까? 마지막으로, 당신은 cat
단지 필요하지 않습니다awk . . . "$file" | . . .
awk -vmax=15 '{len=length($0); if(len>=max){printf("%s, %d at line # %d %s\n", FILENAME, len, NR, $0);}}' file*
당신은 사용할 수 있습니다 wc
:
wc -L fileName
wc -L
.