파일을 가져와 알파벳의 각 문자가 단어 수의 내림차순으로 단어를 시작하는 횟수를 인쇄해야 합니다. 예를 들어, 파일이 다음과 같은 경우:
my nice name is Mike Meller
그러면 출력은 다음과 같아야 합니다.
3 M
2 N
1 I
이 작업을 한 줄로 수행해야 합니다. wc -m
및 와 같은 명령이 있다는 것을 알고 있지만 wc -w
각 문자를 반복하고 동일한 방식으로 인쇄한 다음 원하는 방식으로 정렬하는 방법을 잘 모르겠습니다.
답변1
편도... (같은 단어를 두 번 계산하지 않도록 편집됨)
$ echo "my nice name is Mike Meller" | tr ' ' '\n' | sort -f | uniq -i | sed -nr 's/^([a-z]).*/\U\1/Ip' | uniq -c | sort -r
3 M
2 N
1 I
tr ' ' '\n'
공백을 줄 바꿈으로 변경sort -f
대소문자가 다르더라도 동일한 항목이 함께 있도록 행을 정렬합니다.uniq -i
중복된 단어를 제거하고 대소문자를 무시하세요.sed -nr 's/^([a-z]).*/\U\1/Ip'
첫 번째 문자를 제외한 모든 문자를 제거하고 모든 문자를 대문자로 변경하고 문자로 시작하지 않는 줄을 인쇄하지 마십시오.uniq -c
동일한 행 수 계산sort -r
내림차순 정렬
( echo "my nice name is Mike Meller"
다음으로 교체... cat name-of-your-file
)
답변2
그리고 perl
:
perl -Mopen=locale -lne '
$c{uc $_}++ for /\b\p{Alpha}/g;
END{for (sort {$c{$b} <=> $c{$a}} keys %c) {print "$c{$_} $_"}}'
일부 문자가 분해된 형태로 나타나는지 확인하십시오. 예를 들어, É
입력이 É
사전 결합(U+00E9) 대신(예: E 다음에 U+0301 결합 악센트) 인 경우 사전 결합(U+00E9) 대신 Nor É
로 계산됩니다 .E
É
É
이것이 문제인 경우 가장 좋은 접근 방식은 먼저 텍스트를 분해하고(일부 문자소에는 미리 구성된 형식이 없기 때문에) 문자소 클러스터를 기반으로 작업하는 것입니다. 어쨌든, 다음과 같이 fi
분해하고 싶은 것이 있습니다 .
비교하다:
$ printf 'my fine name is \uc9ric, maybe E\u301ric, certainly not Eric\n' |
perl -Mopen=locale -lne '
$c{uc $_}++ for /\b\p{Alpha}/g;
END{for (sort {$c{$b} <=> $c{$a}} keys %c) {print "$c{$_} $_"}}'
2 E
2 N
2 M
1 C
1 FI
1 É
1 I
그리고:
$ printf 'my fine name is \uc9ric, maybe E\u301ric, certainly not Eric\n' |
perl -Mopen=locale -MUnicode::Normalize -lne '
$c{uc $_}++ for NFKD($_) =~ /\b(?=\p{Alpha})\X/g;
END{for (sort {$c{$b} <=> $c{$a}} keys %c) {print "$c{$_} $_"}}'
2 É
2 M
2 N
1 E
1 I
1 C
1 F
답변3
GNU awk:
gawk '
{ for (i=1; i<=NF; i++) count[toupper(substr($i,1,1))]++ }
END {
PROCINFO["sorted_in"] = "@val_num_desc"
for (key in count) print count[key], key
}
' file
답변4
이게 숙제가 아니길 바라요? ;-) 까다로운 부분은 Meller의 "L"을 두 번 계산하고 싶지 않다는 것입니다. 그렇죠? 그래서 "독특함"이 있습니다.
$cat t
my nice name is Mike Meller
그런 다음 변환을 수행하는 명령 파이프라인이 제공됩니다.
$tr '[a-z]' '[A-Z]' < t | # Convert all to upper case
fold -b -w 1 | # Break into one letter per line
awk -f t.awk | # Pipe the whole mess to awk to count
sort -r -n # Sort in reverse numeric order
awk 스크립트는 별도의 파일로 나누는 것이 가장 좋지만 bash에서는 한 줄에 모두 넣을 수 있습니다.
$cat t.awk
/ / { # Match spaces,
for (c in wc) {dc[c]+=1} # Accumulate word count (wc) into doc count (dc)
split("",wc) # Reset the word count
}
!/ / { # Match non-spaces,
if (wc[$1] == "") wc[$1]=1 # If haven't already seen char in this word, mark it Donny
}
# Finally, output the count and the letter
END {
for (c in wc) {dc[c]+=1} # Accumulate one last time, in case there is no trailing space
for (c in dc) {print c, dc[c]}
}
(나를 위해) 다음과 같은 출력이 생성됩니다.
$tr '[a-z]' '[A-Z]' < t | fold -b -w 1 | awk -f t.awk | sort -r -n
4 M
4 E
3 I
2 N
1 Y
1 S
1 R
1 L
1 K
1 C
1 A