내 디렉토리에는 다음과 같은 내용을 포함하는 여러 파일이 있습니다.
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
는 각 키/값을 반복합니다.arr
print
그리고진주하나의 선:
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