최소 문자로 줄을 찾는 방법


22

일반적인 UNIX 명령을 사용하여 쉘 스크립트를 작성 중입니다. 가장 적은 문자 (공백 포함)가있는 줄을 검색해야합니다. 최대 약 20 줄이있을 수 있습니다.

head -$L | tail -1 | wc -m줄 L의 문자 수를 찾는 데 사용할 수 있다는 것을 알고 있습니다 . 문제는 내가 사용할 수있는 유일한 방법은 값을 비교하여 if 문을 엉망으로 만드는 것입니다.

데이터 예 :

seven/7
4for
8 eight?
five!

4for해당 줄에 문자가 가장 적으므로 반환 됩니다.

필자의 경우 여러 줄의 길이가 가장 짧은 경우 단일 줄을 반환해야합니다. 길이가 최소 인 한 어떤 것이 선택되는지는 중요하지 않습니다. 그러나 다른 상황에서 다른 사용자에게 두 가지 방법을 모두 보여주는 데는 해가되지 않습니다.


5
길이가 4 인 여러 줄이 있으면 어떻게됩니까? 그들도 인쇄해야합니까?
혼돈

필자의 경우 여러 줄의 길이가 가장 짧은 경우 단일 줄을 반환해야합니다. 길이가 최소 인 한 어떤 것이 선택되는지는 중요하지 않습니다. 그러나 다른 상황에서 다른 사용자에게 두 가지 방법을 모두 보여주는 데는 해가되지 않습니다.
Matthew D. Scholefield

답변:


13

펄 방식. 길이가 가장 짧은 동일한 줄이 여러 개있는 경우이 방법은 다음 중 하나만 인쇄합니다.

perl -lne '$m//=$_; $m=$_ if length()<length($m); END{print $m if $.}' file 

설명

  • perl -lne: -n"입력 파일을 한 줄씩 읽습니다"를 의미하며, -l각 입력 줄에서 후행 줄 바꿈이 제거되고 각 print호출에 줄 바꿈이 추가됩니다 . 및 -e각 라인에 적용 할 스크립트입니다.
  • $m//=$_: 정의 되지 않은 경우 $m현재 줄 ( $_)로 설정 합니다 $m. 이 //=연산자는 Perl 5.10.0부터 사용할 수 있습니다.
  • $m=$_ if length()<length($m):의 현재 값의 $m길이가 현재 행의 길이보다 큰 경우 현재 행 ( $_)을로 저장하십시오 $m.
  • END{print $m if $.}: 모든 행이 처리되면 $m가장 짧은 행 의 현재 값을 인쇄하십시오 . if $.라인 번호 (없도록하는 경우에만 발생한다는 $.) 빈 입력 빈 라인을 인쇄하는 피할 정의된다.

또는 파일이 메모리에 들어갈만큼 작기 때문에 다음을 수행 할 수 있습니다.

perl -e '@K=sort{length($a) <=> length($b)}<>; print "$K[0]"' file 

설명

  • @K=sort{length($a) <=> length($b)}<>: <>여기에 요소가 파일의 행인 배열이 있습니다. 는 sort길이에 따라 정렬하고 정렬 된 줄은 배열로 저장됩니다 @K.
  • print "$K[0]": 배열의 첫 번째 요소 인 @K가장 짧은 줄을 인쇄합니다 .

가장 짧은 줄을 모두 인쇄 하려면

perl -e '@K=sort{length($a) <=> length($b)}<>; 
         print grep {length($_)==length($K[0])}@K; ' file 

1
-C바이트 수 대신 문자 수로 길이를 측정하려면 추가하십시오 . UTF-8 로켈에서 (2 대 3) $$보다 바이트 수가 적지 만 더 많은 문자 (2 대 1)가 있습니다.
Stéphane Chazelas

17

sqlite3:

sqlite3 <<EOT
CREATE TABLE file(line);
.import "data.txt" file
SELECT line FROM file ORDER BY length(line) LIMIT 1;
EOT

저것은 내가 여기에서 가장 좋아하는 SQL이고, 결코 생각해 본 적이 없다.
chaos

2
이 코드 골프 상태 영리하다
shadowtalker

2
이것은 전체 파일을 메모리로 읽거나 두 번째 온 디스크 사본을 작성합니까? 그렇다면 영리하지만 비효율적입니다.
John Kugelman은 Monica

1
@JohnKugelman 아마도 전체 4 줄을 임시 메모리 전용 데이터베이스에 담을 것입니다 strace. 정말 큰 파일로 작업해야하고 시스템이 스왑되지 않는 경우 파일 이름을 추가하여 파일을 강제로 적용하면 sqlite3 $(mktemp)모든 데이터가 디스크에 기록됩니다.
FloHimself 2016 년

"" "xaa : 8146 : 이스케이프 처리되지 않은"문자 "" "및" ""xaa : 8825 : 예상 한 1 개의 열이 있지만 2 개의 추가 항목이 무시 됨 "" ". 파일은 각 줄당 1 개의 json 문서로 구성됩니다. .
아메 도프

17

awk처음 발견 된 최소 행을 인쇄하기 위한 솔루션 의 변형은 다음과 같습니다 .

awk '
  NR==1 || length<len {len=length; line=$0}
  END {print line}
'

하나의 조건으로 간단히 확장하여 모든 최소 줄을 인쇄 할 수 있습니다.

awk '
  length==len {line=line ORS $0}
  NR==1 || length<len {len=length; line=$0}
  END {print line}'
'

12

파이썬은 상당히 간결하게 나오고 코드는 주석에서 말하는 것을 수행합니다.

python -c "import sys; print min(sys.stdin, key=len),"

마지막 쉼표가 모호합니다. print 문이 추가 줄 바꿈을 추가하지 못하게합니다. 또한 다음과 같이 0 줄을 지원하는 Python 3에서 이것을 작성할 수 있습니다.

python3 -c "import sys; print(min(sys.stdin, key=len, default='').strip('\n'))"


주석은 무엇을 말합니까?
mikeserv 2016 년

@mikeserve : "len을 키로 사용하여 sys.stdin의 최소값을 인쇄합니다";-)
Steve Jessop

1
아 이진 크기, 종속성 크립 또는 실행 시간에 대해 아무것도?
mikeserv 2016 년

2
@ mikeserv : 아니오, 작은 글씨는 주석에 없습니다. 그것은 "표범을 조심하십시오"라고 표시된 문 뒤에 지하실에 잠긴 서류 정리 캐비닛의 자문 전단지에 있습니다.
Steve Jessop

잡았다- 디스플레이에.
mikeserv 2016 년

10

나는 항상 순수한 쉘 스크립팅 (exec 없음)으로 솔루션을 좋아합니다.

#!/bin/bash
min=
is_empty_input="yes"

while IFS= read -r a; do
    if [ -z "$min" -a "$is_empty_input" = "yes" ] || [ "${#a}" -lt "${#min}" ]; then
        min="$a"
    fi
    is_empty_input="no"
done

if [ -n "$a" ]; then
    if [ "$is_empty_input" = "yes" ]; then
        min="$a"
        is_empty_input="no"
    else
        [ "${#a}" -lt "${#min}" ] && min="$a"
    fi
fi

[ "$is_empty_input" = "no" ] && printf '%s\n' "$min"

참고 :

입력에 NUL 바이트에 문제가 있습니다. 따라서 대신에 printf "ab\0\0\ncd\n" | bash this_script인쇄 ab합니다 cd.


이것은 정말로 가장 순수한 것입니다. 그러나 테스트의 어색함은 대신 bash중간 결과를 파이프로 유도 sort합니다.
오리온

2
exec를 벤치마킹 해 보셨습니까 ? 솔루션 대 다른 사람? 다음exec! 의 성능 차이를 비교 한 것 입니다 . 그리고 exec 없음! 비슷한 문제에 대한 해결책. 별도의 프로세스를 실행하는 var=$(get data)것은 데이터 흐름을 단일 컨텍스트로 제한하기 때문에 형태가 스파이더 일 때 매우 유리하지 않습니다. 그러나 파이프 라인을 통해 데이터 스트림으로 이동할 때 적용되는 각 exec는 일반적으로 도움이됩니다. 필요한 경우에만 모듈 식 프로그램을 적용하십시오.
mikeserv 2016 년

1
@DigitalTrauma-확장 된 연속 자릿수 문자열은 다른 확장 문자열보다 쉘 인용이 필요한 조건에서 어느 정도 면제되지 않습니다. 많은 셸이 사전 설정 환경 구성을 허용하지만 $IFS기본값이없는 경우에도 숫자를 구분 하지 않으므로 특히 신뢰할 수있는 기본값이 아닙니다. $IFS$IFS
mikeserv 2016 년


1
의견과 공감에 대해 모두 감사합니다 (일부 담당자는 내 대답을 수정하기 위해 @cuonglm으로 가야합니다). 일반적으로 다른 사람들에게 순수 쉘 스크립팅을 매일 연습하는 것은 좋지 않지만 정적 링크 이외의 다른 것이없는 극한 상황에서는이 기술이 매우 유용 /bin/sh합니다. SunOS4 호스트가 /usr손실되거나 일부 .so손상 되어 여러 번 발생 했으며 현재 Linux 시대에는 임베디드 시스템이나 부팅 실패 시스템의 initrd와 비슷한 상황이 종종 발생합니다. BusyBox는 우리가 최근에 얻은 위대한 것들 중 하나입니다.
yaegashi 2016 년

9

여기에 순수한 zsh해결책 (에서 최소 길이로 모든 줄을 인쇄합니다 file) :

IFS=$'\n'; print -l ${(M)$(<file):#${~${(o@)$(<file)//?/?}[1]}}

입력 예 :

seven/7
4for
8 eight?
five!
four

출력은 다음과 같습니다

4for
four

나는 그것이 짧은 설명이 필요하다고 생각합니다 :-)


먼저 내부 필드 구분 기호를 줄 바꿈으로 설정합니다.

IFS=$'\n';

여태까지는 힘들었지 만 플래그를 print사용하여 -l공백 대신 줄 바꿈으로 구분하여 결과를 인쇄합니다.

이제 우리는 내부에서 시작합니다.

$(<file)

파일을 한 줄씩 읽고 배열로 취급합니다. 그때:

${(o@)...//?/?}

o플래그 결과가 오름차순으로 정렬되어야 함을 말한다 @너무 어레이와 같은 결과를 처리하는 수단. ( //?/?) 뒤의 부분 은 모든 문자를로 대체하는 대체 ?입니다. 지금:

${~...[1]}

우리는 첫 번째 배열 요소를 가지고 [1]는 이제 귀하의 경우, 짧은이다 ????.

${(M)$(<file):#...}

각 배열 요소에 대해 개별적으로 일치가 수행되고 일치하지 않는 배열 요소가 제거됩니다 ( M). 일치하는 각 요소 ????(4 자)는 배열에 유지됩니다. 나머지 요소는 4 자 (가장 짧은 것) 인 요소입니다.

편집 : 가장 짧은 줄 중 하나만 필요한 경우이 수정 된 버전은 첫 번째 줄을 인쇄합니다.

IFS=$'\n'; print -l ${${(M)$(<file):#${~${(o@)$(<file)//?/?}[1]}}[1]}

8
tr -c \\n 1 <testfile |   #first transform every [^\n] char to a 1
grep -nF ''           |   #next get line numbers
paste -d: - testfile  |   #then paste it together with itself
sort  -t: -nk2,2          #then sort on second field

... 그리고 우승자는 ... 2 번 줄입니다.

2:1111:4for
4:11111:five!
1:1111111:seven/7
3:11111111:8 eight?

그러나 문제는 모든 라인의 길이가 두 배 이상 길어야 LINE_MAX 가 효과적으로 반감 된다는 것 입니다. 원인은 그것이 무엇을 사용하고 있기 때문입니다-무엇, 기본 1? -선의 길이를 나타냅니다. 비슷하고 더 깔끔한 접근 방식은 해당 정보를 스트림으로 압축하는 것입니다. 나에게 나타나는 선을 따르는 첫 번째 아이디어는 내가해야한다는 unexpand것입니다.

tr -c \\n \  <testfile    |   #transform all [^\n] to <space>
unexpand -t10             |   #squeeze every series of 10 to one tab
grep -nF ''               |   #and get the line numbers
sed    's/:/!d;=;:/;h;:big    #sed compares sequential lines
$P;$!N; /\(:[^ ]*\)\( *\)\n.*\1.*\2/!D     #newest line is shorter or...
        g;/:./!q;b big'   |   #not; quit input entirely for blank line
sed -f - -e q testfile        #print only first occurrence of shortest line

그 인쇄 ...

2
4for

또 다른 하나 sed:

sed -n '/^\n/D;s/\(.\)\(\n.*\)*/\1/g
$p;h;   s// /g;G;x;n;//!g;H;s// /g
G;      s/^\( *\)\(\n \1 *\)\{0,1\}\n//
D'      <infile >outfile

이 구문은 표준을 준수하지만 오래된 sed것이 \(reference-group\)\{counts\}올바르게 처리 된다는 보장 은 없습니다.

기본적으로 동일한 정규 표현식을 반복적으로 입력에 적용하므로 컴파일 할 때 매우 유용합니다. 그 패턴은 다음과 같습니다

\(.\)\(\n.*\)*

다른 방식으로 다른 문자열과 일치합니다. 예를 들면 다음과 같습니다.

string1\nstring2\nstring3

...과 일치 s\1''있는 널 (null) 문자열 \2.

1\nstring2\nstring3

...과 일치 1\1\nstring2\nstring3\2

\nstring2\nstring3

...과 일치 \n\1''있는 널 (null) 문자열 \2. \n패턴 공간의 헤드에서 ewline이 발생할 가능성이있는 경우 문제가 될 수 있지만, 이를 방지하기 위해 /^\n/D, 및 //!g명령이 사용됩니다. 나는 [^\n]이 작은 스크립트에 대한 다른 요구를 사용 하여 이식성을 염려했으며 종종 잘못 해석되는 많은 방법에 만족하지 못했습니다. 게다가 .빠릅니다.

\nstring2
string1

... 일치 \n하고 s다시 \1그리고 둘 다에서 ''null 문자열을 가져옵니다 \2. 빈 줄이 전혀 일치하지 않습니다.

패턴이 g전체적으로 적용되는 경우 , 가장 왼쪽의 표준 바이어스와 오른쪽의 오른쪽 \newline 바이어스 모두 두 개의 바이어스 가 카운터 밸런스되어 스킵됩니다. 몇 가지 예 :

s/\(.\)\(\n.*\)*/\1:\2/g
s/\(.\)\(\n.*\)*/\2\1:/g
s/\(.\)\(\n.*\)*/\1: /g
s/\(.\)\(\n.*\)*/ :\2/g

... 다음 문자열 모두 가 연속으로 적용 되지 않는 경우 ...

string1\nstring2

... 그것을 ...

s:t:r:i:n:g:1:\nstring2
s:t:r:i:n:g:\nstring21:
s:t:r:i:n:g:1: 
 : : : : : : :\nstring2

기본적으로 나는 정규 표현식을 사용하여 항상 적용 할 패턴 공간의 첫 번째 줄만 처리합니다. 이를 통해 루프 테스트에 의존하지 않고 가장 짧은 유지 일치 라인과 가장 최근 라인의 두 가지 버전을 저글링 할 수 있습니다. 적용된 모든 대체는 전체 패턴 공간을 한 번에 처리합니다.

리터럴 문자열 / 문자열 비교에는 다른 버전이 필요하므로 모든 문자가 동일하게 보장되는 각 행의 버전이 있어야합니다. 그러나 물론 하나 또는 다른 하나가 실제로 가장 짧은 입력 라인에서 실제로 감기면 출력으로 인쇄 된 라인은 아마도 비교를 위해 위생 처리 / 균질화 된 라인이 아닌 원래 버전의 라인이어야합니다. 그래서 나는 두 가지 버전이 필요합니다.

불행히도 또 다른 필요성은 동일한 것을 처리하기 위해 많은 버퍼 전환이 필요합니다. 그러나 적어도 어느 버퍼도 전류를 유지하는 데 필요한 4 라인 이상을 초과하지 않으므로 끔찍하지 않을 수도 있습니다.

어쨌든, 각주기마다 가장 먼저 발생하는 일은 기억 된 줄의 변형입니다. 실제로 저장된 유일한 사본은 리터럴 원본이므로 ...

^               \nremembered line$

... 그리고 나서 next 입력 라인은 오래된 버퍼를 덮어 씁니다. 하나 이상의 문자를 포함하지 않으면 효과적으로 무시됩니다. q처음 나타나는 빈 줄 에 맞추는 것이 훨씬 쉽지만 테스트 데이터에는 많은 양이 있었고 여러 단락을 처리하고 싶었습니다.

따라서 문자가 포함되어 있으면 리터럴 버전이 기억 된 행에 추가되고 간격 비교 버전은 다음과 같이 패턴 공간의 헤드에 배치됩니다.

^   \n               \nremembered line\nnew$

마지막으로 해당 패턴 공간에 대체가 적용됩니다.

s/^\( *\)\(\n \1 *\)\{0,1\}\n//

따라서 줄 바꿈이 기억할 줄을 포함하는 데 필요한 공간에 하나 이상의 문자를 포함하는 데 필요한 공간에 들어가면 처음 두 줄만 대체됩니다.

결과에 관계없이 패턴 공간의 첫 번째 라인은 D다시 시작하기 전에 항상 사이클 끝에서 엘레 트됩니다. 이것은 새 줄이 마지막 줄보다 짧으면 ...

new

... 첫 번째 줄 바꿈 문자에서만 항상 제거되는 사이클의 첫 번째 대체로 다시 전송되므로 전체가 유지됩니다. 그러나 그것이 문자열이 아니면 ...

remembered line\nnew

... 다음 사이클을 시작하고 첫 번째 치환은 문자열에서 제거합니다 ...

\nnew

... 매번.

마지막 줄에서 기억 된 줄은 표준 출력으로 인쇄되므로 주어진 예제 데이터의 경우 다음과 같이 인쇄됩니다.

4for

그러나 진지하게 사용하십시오 tr.



줄 번호를 삽입해야합니까? OP에 대한 필자는 가장 짧은 줄만 필요하며 반드시 그 줄의 줄 번호가 아니라는 것입니다. 완전성을 위해 그것을 보여주는 데 아무런 해가 없다고 생각합니다.
디지털 외상

@DigitalTrauma-아마, 아마 아닙니다. 그러나 그것들이 없으면 매우 유용하지 않으며 매우 저렴합니다. 스트림을 작업 할 때 항상 원본 입력을 출력에서 ​​동일하게 재생하는 수단을 포함하는 것을 선호합니다. 행 번호는 여기에서 가능합니다. 예를 들어 첫 번째 파이프 라인의 결과를 다음과 같이 바꾸려면 : REINPUT | sort -t: -nk1,1 | cut -d: -f3-. 두 번째는 sed --expression꼬리에 다른 스크립트를 포함시키는 간단한 문제입니다 .
mikeserv 2016 년

@DigitalTrauma-아, 그리고 첫 번째 예에서 라인 번호 sort 입력에서 동일한 길이의 라인이 발생할 때 타이 브레이커로서의 동작에 영향을 미칩니다. 따라서 가장 이른 라인은 항상 맨 위에 떠 있습니다.
mikeserv 2016 년

7

시험:

awk '{ print length, $0 }' testfile | sort -n | cut -d" " -f2- | head -1

아이디어는 awk각 줄의 길이를 먼저 인쇄하는 데 사용 하는 것입니다 . 이것은 다음과 같이 나타납니다 :

echo "This is a line of text" | awk '{print length, $0}'
22 This is a line of text

그런 다음에 의해 선을 정렬 할 글자 수를 사용 sort, cut개수 없애과 head첫 번째 줄 (최소한의 문자 하나)를 유지합니다. 물론 tail이 경우 가장 많은 문자가있는 줄을 얻는 데 사용할 수 있습니다 .

(이 답변 에서 채택되었습니다 )


논리의 경우 +1이지만 모든 경우에 작동하지는 않습니다. 두 줄의 문자 수가 같고 최소 인 경우 그것은 당신에게 발생하는 첫 번째 줄만을 줄 것입니다.head -1
Thushi

가장 긴 줄을 얻으려면 사용하는 것보다 정렬을 반대로하는 것이 조금 더 효율적입니다 tail( head나머지 입력을 읽지 않고 작업이 완료되는 즉시 종료 할 수 있음).
Toby Speight

@Thushi 줄 번호를 인쇄 한 후 줄 번호를 인쇄 한 후 줄 1과 번호가 같은 줄을 제외한 모든 줄을 제거하여 가장 짧은 줄을 모두 출력 할 수 있습니다.
Matthew D. Scholefield 2016 년

5

POSIX awk 사용시 :

awk 'FNR==1{l=$0;next};length<length(l){l=$0};END{print l}' file

둘 이상의 행에 동일한 수의 문자가 있고 최소값 인 경우 작동하지 않습니다.
Thushi

@Thushi : 첫 번째 최소 행을보고합니다.
cuonglm 2016 년

예. 그러나 올바른 출력이 아닙니다? 다른 줄조차도 문자 수가 가장 적습니다.
Thushi

1
@Thushi : OP 요구 사항에는 언급되지 않았으며 OP의 업데이트를 기다리고 있습니다.
cuonglm 2016 년

3
내가 생각하지 않는 L변수의 이름을 선택하는 최선의 편지를했다 : 같은 D의 뭔가 min일을 만들 것 더 명확
fedorqui

3

@mikeserv의 아이디어를 빌리기 :

< testfile sed 'h;s/./:/g;s/.*/expr length "&"/e;G;s/\n/\t/' | \
sort -n | \
sed -n '1s/^[0-9]+*\t//p'

첫 번째 sed는 다음을 수행합니다.

  • h 원래 행을 보류 버퍼에 저장
  • 줄의 모든 문자를 다음으로 바꿉니다. :이것은 코드 삽입의 위험을 제거하기위한 것입니다.
  • 전체 줄을 다음과 같이 바꾸십시오 expr length "whole line"-이것은 평가 될 수있는 쉘 표현식입니다
  • 전자 명령에s A는 GNU가 확장 나오지 패턴 영역을 평가하고 패턴 영역에서 결과 다시 넣어.
  • G 줄 바꿈과 보류 공간의 내용 (원래 줄)을 패턴 공간에 추가합니다.
  • 마지막 s은 개행을 탭으로 바꿉니다.

문자 수는 이제 각 줄의 시작 부분에있는 숫자이므로 sort -n줄 길이별로 정렬됩니다.

마지막 sed은 첫 번째 (가장 짧은) 행과 행 길이를 제외한 모든 행을 제거하고 결과를 인쇄합니다.


1
@ mikeserv 예 expr여기가 더 좋다고 생각 합니다. 예, e각 줄마다 쉘을 생성합니다. sed 표현식을 편집하여 문자열의 각 문자 :를 코드 주입 가능성을 제거해야한다고 생각하는 eval 이전으로 바꿉니다 .
디지털 외상

나는 보통 xargs expr개인적 으로 선택 하지만 중간 껍질을 피하는 것 외에는 더 스타일리쉬 한 것입니다. 어쨌든 마음에 든다.
mikeserv 2016 년

3

하나의 sed표현으로 모든 것이 가능하다는 것이 나에게 일어났다 . 예쁘지 않습니다.

$ sed '1h;s/.*/&\n&/;G;:l;s/\n[^\n]\([^\n]*\)\n[^\n]/\n\1\n/;tl;/\n\n/{s/\n.*//;x};${x;p};d' testfile
4for
$ 

이것을 분해 :

1h            # save line 1 in the hold buffer (shortest line so far)
s/.*/&\n&/    # duplicate the line with a newline in between
G             # append newline+hold buffer to current line
:l            # loop start
s/\n[^\n]\([^\n]*\)\n[^\n]/\n\1\n/
              # attempt to remove 1 char both from current line and shortest line
tl            # jump back to l if the above substitution succeeded
/\n\n/{       # matches if current line is shorter
  s/\n.*//    # remove all but original line
  x           # save new shortest line in hold buffer
}
${            # at last line
  x           # get shortest line from hold buffer
  p           # print it
}
d             # don't print any other lines

OS X에서 사용되는 BSD는 줄 바꿈으로 조금 더 까다 롭습니다. 이 버전은 sed의 BSD 및 GNU 버전 모두에서 작동합니다.

$ sed -e '1h;G;s/\([^\n]*\)\(\n\)\(.*\)/\1\2\1\2\3/;:l' -e 's/\(\n\)[^\n]\([^\n]*\n\)[^\n]/\1\2/;tl' -e '/\n\n/{s/\n.*//;x;};${x;p;};d' testfile
4for
$

이는 모범 사례 답변을 제공하려는 진지한 시도보다 "가능하기 때문에"답변입니다. 코드 콜프를 너무 많이 연주했음을 의미합니다.


@mikeserv man sedOS X에서 : "이스케이프 시퀀스 \ n은 패턴 공간에 포함 된 개행 문자와 일치합니다 . " 따라서 GNU sed는 \n정규식과 교체에서 허용하지만 BSD \n는 정규식 에서만 허용하고 대체는 허용 하지 않습니다.
디지털 외상

\n패턴 공간에서를 빌리 는 것은 좋은 생각이며 두 번째 s///표현식 에서 작동 하지만 s/.*/&\n&/표현식은 \n이전에 없었던 패턴 공간에 a 를 삽입합니다 . 또한 BSD sed는 레이블 정의 및 분기 다음에 리터럴 줄 바꿈이 필요한 것으로 보입니다.
디지털 외상

1
이러한 줄 바꿈은 매개 변수 구분 기호입니다. 최소한 임의 매개 변수를 허용하는 명령을 구분해야합니다. 최소한 사양이 말하는 것입니다. 스펙은 또한 sed스크립트 가 줄 바꿈으로 끝나지 않는 것을 제외하고 텍스트 파일이어야 한다고 말한다 . 따라서 일반적으로 별도의 인수로도 구분할 수 있습니다 sed -e :\ label -e :\ label2. 1h어쨌든 하고 있기 때문에 x;H개행을 얻기 위해 기반으로 일부 논리로 전환 할 수 있습니다 D. 개행 줄을 w /으로 당기지 않고 사이클이 끝날 때 패턴 공간에서 선행 개행 을 자를 수 있습니다 .
mikeserv 2016 년

@mikeserv 니스. 예, G첫 번째 작업을 수행 하고 s///표현식을 변경하여 필요한 줄 바꿈을 삽입했습니다 . 그것을 사용하여 -e나누면 문자 그대로 줄 바꿈없이 하나의 긴 줄로 갈 수 있습니다.
디지털 외상

\n탈출을 위해 spec'd되고 sed도의 좌, 나는 그 POSIX 브래킷 표현은 모든 문자가 특별한 의미를 잃게하는 방식으로 spec'd된다는 점을 제외하고 그대로 사양의 진술 생각 - (명시 적으로 포함하여 \\) - 대괄호를 제외한 범위 내에서 대시는 범위 구분 기호로 사용되며 점, 같음, 캐럿, 데이터 정렬, 등가, 부정 및 클래스의 콜론입니다.
mikeserv

2

또 다른 펄 솔루션 : 라인을 해시 키에 저장합니다. 해시 키는 라인 길이입니다. 그런 다음 최소 키를 사용하여 줄을 인쇄하십시오.

perl -MList::Util=min -ne '
    push @{$lines{ length() }}, $_;
} END {
    print @{$lines{ min keys %lines }};
' sample 
4for

당신은 사용할 수 있습니다 push @{$lines{+length}};print @{$lines{+min keys %lines}};:) 적은 타이핑
cuonglm

내가 골프라면, 나도 변수 이름 "선"을 사용하지 않았을 :perl -MList::Util=min -nE'push @{$l{+length}},$_}END{say@{$l{min keys%l}}' sample
글렌 잭맨

골프화되지 않은 버전의 경우 +1 (작동합니다!)이지만 모든 변형 인쇄에만 적용됩니다 . – 비밀스러운 성격 perl을 지니고 있지 않은 우리에게는 약간 비참 perl합니다. BTW. golfed say를 인쇄 end.of 출력에서 가짜 빈 줄.
Peter.O

2

가장 짧은 줄만 얻으려면 :

f=file; sed -n "/^$(sed 's/./1/g' $f | sort -ns | sed 's/././g;q')$/{p;q}" $f

가장 짧은 보푸라기를 얻으려면로 변경하십시오 {p;q}.p


또 다른 방법 (약간 특이한)은 sort실제 작업을 수행하는 것입니다 길이별로 정렬을 입니다. 단선에서도 비교적 느리며 선 길이가 길어질수록 획기적으로 느려집니다.
그러나 중복 키를 사용 하여 정렬하는 아이디어는 매우 흥미 롭습니다. 다른 사람들이 흥미롭고 유익한 것을 발견 할 수 있도록 게시하고 있습니다.

작동 방식 :
동일한 키의 길이 변형을 기준으로 정렬 – key 1전체 라인에 걸쳐 있음
각 연속 키 변형은 파일의 가장 긴 라인 길이까지 키 길이를 한 문자 씩 증가시킵니다 (로 결정 wc -L)

첫 번째 (정렬 된) 가장 짧은 줄만 얻으려면 :

f=file; sort -t'\0' $(seq -f "-k1.%0.0f" $(<"$f" wc -L) -1 1) "$f" | head -n1

이는 다음과 같습니다.

f=file.in; 
l=$(<"$f" wc -L)
k=$(seq -f "-k1.%0.0f" $l -1 1) 
sort -st'\0' $k "$f" | head -n1

2

빈 줄이 가장 짧은 줄로 간주되지 않고 빈 줄이 있다고 가정하면 다음과 같은 순수한 AWK가 작동합니다.

awk '
    {
        len   = length;
        a[$0] = len
    }
    !len { next }
    !min { min = len }
    len < min { min = len }
    END {
        for (i in a)
            if (min == a[i])
                print i
    }
' infile.txt

2

정렬을 사용하는 것은 어떻습니까?

awk '{ print length($0) "\t" $0 }' input.txt | sort -n | head -n 1 | cut -f2-

1

GNU awk로

gawk '
    {
         a[length]=$0
    };
    END
    {
        PROCINFO["sorted_in"]="@ind_num_asc";
        for (i in a)
        {
            print a[i]; 
            exit
        }
    }
    ' file
  • 행 길이별로 인덱스 된 배열로 각 행을 읽습니다.

  • 설정 PROCINFO["sorted_in"]@ind_num_asc힘을 배열 스캔이 배열 인덱스에 의해 주문하는 수치 적 분류

  • PROCINFO위와 같은 방식으로 설정 하면 가장 작은 길이의 라인이 배열 순회에서 먼저 선택됩니다. 따라서 배열에서 첫 번째 요소를 인쇄하고 종료하십시오.

이것은 nlogn다른 접근법 중 일부가 제 n시간에 있다는 단점이 있습니다


1

중간 수준 아니오 쉘 도구 방법, sed또는 awk:

f=inputfile
head -n $(xargs -d '\n' -L 1 -I % sh -c 'exec echo "%" | wc -c' < $f | 
          cat -n | sort -n -k 2 | head -1 | cut -f 1)  $f | tail -1

$f변수 가 필요없는 것이 좋습니다 . 나는 tee어떻게 든 가능할 수있는 개념을 가지고있다 .
agc
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.