"*"로 끝나는 줄 수 계산

"*"로 끝나는 줄 수 계산

내 디렉토리에는 다음과 같은 내용을 포함하는 여러 파일이 있습니다.

Wood *
Nails
Large Hammer *

일부 이름에는 뒤에 별표가 있고 일부는 그렇지 않습니다. 이러한 유형의 콘텐츠가 포함된 파일이 여러 개 있습니다. 각 파일에는 제품이 있을 수도 있고 없을 수도 있습니다.하나의옆에는 별이 있습니다. 모든 파일에서 각 제품의 별표 발생 횟수를 계산하는 bash 스크립트를 만들어야 합니다. 예를 들어 출력은 다음과 같아야 합니다.

Wood 12
Yellow Lamps 6
Nails 4
...

이는 모든 파일에서 나무 옆에 별 12개, 램프 옆에 별 6개 등이 발견되었음을 의미합니다.

C로 구문 분석하는 것은 매우 쉽지만 바이너리를 실행하고 싶지 않습니다. 나는 쉘 스크립트를 원하지만 grep과 awk에 능숙하지 않지만 이것이 필요하다고 확신합니다.

별 자체를 세는 방법은 알고 있지만 어떤 별이 어떤 제품에 속하는지 어떻게 추적하는지 잘 모르겠습니다.

답변1

이와 같이:

awk '$NF=="*"{$NF=""; arr[$0]++}END{for (i in arr) print i arr[i]}' ./*
  • $NF기본값은 공백으로 구분된 최신 문자열입니다.
  • 주요 비결은 arr현재 단어가 있는 곳에 ay라는 관련 단어를 만드는 것입니다.열쇠그리고 증가
  • 아, 우리 END는 각 키/값을 반복합니다.arrprint

그리고하나의 선:

perl -anE '
    if ($F[-1] eq "*") {
        $k = join " ", @F[0..@F-2];
        $a->{$k}++
    }
    END{say "$_ $a->{$_}" for keys %$a}
' ./*

-a나뉘다@F기본 배열의 패턴

답변2

다음을 수행할 수 있습니다.

sed -n 's/[[:blank:]]*\*$//p' ./* |
  LC_ALL=C sort |
  LC_ALL=C uniq -c |
  sort -rn

<blanks>*끝 부분의 줄을 제거하고 ( p그러한 대체 항목이 있는 줄만 인쇄함) sort | uniq -c고유한 줄 수를 계산하는 데 사용됩니다(C 로케일에서는 바이트 간 비교입니다).

답변3

이것이 성능에 영향을 미칠지 확실하지 않습니다. (매우 큰 파일이 있는 경우 이 명령은 느려져야 한다고 생각합니다):

grep -Fh '*' | tr -s ' ' | sort | uniq -c

휴대성이 향상되었습니다.

grep -Fh '*' * 2>/dev/null | tr -s ' ' | sort | uniq -c

하위 디렉터리에 검색하려는 파일이 더 많이 포함되어 있는 경우:

grep -Fh '*' **/* 2>/dev/null | tr -s ' ' | sort | uniq -c | sed 's/.$//'

또는 다음을 사용하지 마십시오 2>/dev/null.

find . -type f -exec grep -Fh '*' {} + | tr -s ' ' | sort | uniq -c | sed 's/.$//'

이 부분은 grep -Fh '*'끝에 가 있는 모든 줄이 일치함을 의미합니다. 패턴과 일치하는 파일 이름의 인쇄를 억제하고 리터럴 문자열을 사용할 때 사용됩니다("*"는 패턴이 아닌 문자열로 동작함). 예를 들어 각 줄 사이의 중복 공백을 제거하고 있습니다.*-h-F
tr -s ' '

Need *
Word   buzz *
Need *
More   *
More *
Word   *
More   *
More *
Word   *
Word   *
Need *
More *

tr명령은 이를 다음과 같이 구문 분석합니다.

Need *
Word buzz *
Need *
More *
More *
Word *
More *
More *
Word *
Word *
Need *
More *

위의 내용은 다음과 같은 출력을 얻기 위해 파이프됩니다 sort.

More *
More *
More *
More *
More *
Need *
Need *
Need *
Word *
Word *
Word *
Word buzz *

마지막으로 uniq -c원하는 각 단어의 발생 횟수를 줄 앞에 붙입니다.

정렬 명령은 중요합니다. 사용하지 않으면 예상 결과가 달라집니다.

위의 출력을 기반으로 최종 출력(사용됨 uniq -c)은 다음과 같습니다.

5 More *
3 Need *
3 Word *
1 Word buzz *

삭제하려면 파이프를 통해 마지막 문자를 제거하거나 다음을 *수행할 수 있습니다 .sed*

grep -Fh '*'  * | tr -s ' ' | sort | uniq -c | sed 's/.$//'
#or
grep -Fh '*' * | tr -s ' ' | sort | uniq -c | sed 's/\*//'

여기에서는 원하는 출력을 얻기 위해 여러 명령을 사용했기 때문에 이를 달성하는 더 좋은 방법이 있다고 생각하고 희망합니다. 앞서 말했듯이 이로 인해 성능이 저하될 수 있습니다.

답변4

bash를 사용하거나 awk를 사용하는 것이 좋지만 (GNU) sed에서 이 작업을 수행하는 것이 좋습니다.

s:  *: :g
/\*$/!s:$: :
G
s:([^\n]+) (\*?)(.*\n)\1 (\**)\n:\3\1 \4\2\n:
s:^\n::
h;$!d
s:\n$::
:u2d
    s:\*:<<123456789*01>:m
    s:(.)<.*\1(\**.).*>:\2:m
tu2d

다음 두 개의 입력 파일(vim 디스플레이)을 사용하여 테스트했습니다. 첫 번째는 Edgar Magalon의 답변에서 나온 것입니다.

Need *         |Need
Word   buzz *  |Word   buzz
Need *         |Need
More   *       |More *
More *         |More *
Word   *       |Word
More   *       |More *
More *         |More *
Word   *       |Word
Word   *       |Word
Need *         |Need
More *         |More *
~              |~
~              |~
input1          input2

결과:

~$ sed -rf script.sed input1 input2
Word 3
More 10
Word buzz 1
Need 3

관련 정보