일
여기서 매개변수는 파일 이름입니다! 파일에 텍스트가 포함되어 있습니다. 스크립트의 임무는 어떤 단어가 다른 단어에 가장 자주 포함되는지 결정하는 것입니다.
입력 및 출력 예
(예: 텍스트는 다음과 같습니다. 공을 치다 축구 농구 눈덩이 - 공이 다른 세 세계의 일부이기 때문에 공이 승자입니다.)
내 코드 소파
지금까지 이 코드를 작성했지만 모든 출력에 대해 작동하지는 않습니다.
!/bin/sh
awk '{for(i=2;i<NF;i++) {s=$i; for(j=i+1;j<=NF;j++) print s=s FS $j}}' $1 | sort | uniq -c | sort -k1,1rn -k2 | sed 's/ *[^ ]* *//;q' | cut -f1 -d" "
답변1
단어 목록이 이라는 파일에 있고 words
각 줄에 단일 단어가 있는 경우( tr ' ' '\n' <originalwords >words
원래 목록을 여러 줄로 분할하기 위해 를 사용하여 생성되었을 수 있음) 루프는
while IFS= read -r word; do
grep -F -o -e "$word" words
done <words | awk '{ c[$0]++; if (c[$0] > c[w]) w = $0 } END { print w }'
목록에 있는 단어의 일부로 가장 많이 나타나는 단어를 출력합니다(또는 많은 단어가 동일하게 여러 번 나타나는 경우 목록에서 처음 발생한 단어 중 하나).
이는 목록 자체를 목록과 일치시킬 패턴 집합으로 사용하여 수행합니다. -o
개별 줄에 일치하는 하위 문자열이 반환되도록 요청합니다 .
질문에 주어진 목록을 사용하여 루프 단독의 출력은 다음과 같습니다.
play
ball
ball
ball
ball
football
basketball
snowball
그런 다음 이 단어들을 세어보고 가장 자주 나오는 단어를 선택하면 됩니다.
임시 파일 처리가 포함된 완전한 스크립트:
#!/bin/sh
tmpfile=$(mktemp)
trap 'rm -f "$tmpfile"' EXIT # delete temporary file upon exiting
tr -s ' ' '\n' <"${1:-/dev/stdin}" >"$tmpfile" # convert into word list
while IFS= read -r word; do
grep -F -o -e "$word" "$tmpfile"
done <"$tmpfile" | awk '{ c[$0]++; if (c[$0] > c[w]) w = $0 } END { print w }'
지정된 파일이 없으면 스크립트는 표준 입력에서 추가로 읽습니다.
답변2
awk '{
for (i=1; i<=NF; i++) {
uwords[$i] = 0
allwords[++idx] = $i
}
}
END {
if (idx == 0) exit
max = 0
for (w in uwords) {
count = 0
for (i=1; i<=idx; i++) {
if (allwords[i] ~ w) count++;
}
if (count > max) {
max = count
maxw = w
}
}
print maxw
}'
입력을 스캔하고 고유 단어 목록과 모든 단어 목록을 추출합니다. (고유한 단어 목록은 필요하지 않을 것 같지만 입력이 큰 경우 작업을 더 효율적으로 만들 수 있습니다.) 그런 다음 각 고유 단어에 대해 파일의 단어 중 몇 개가 일치하는지 계산합니다. (따라서 파일에 가 포함되어 있으면 football football football
3으로 계산됩니다 ball
.) 가장 많이 일치하는 파일을 추적하세요.
동점인 경우 uwords
(고유 단어) 배열에서 처음 나타나는 단어를 보고합니다. 이것이 반드시 파일에 나타나는 첫 번째 항목은 아니며 알파벳순으로 첫 번째 항목도 아닙니다.
단어에 다음이 포함된 경우 예기치 않은 결과가 발생할 수 있습니다..
, *
또는 [
.
Kusalananda의 shell+awk 접근 방식을 선호하지만 극단적인 경우 오류를 원하지 않는 경우 다음을 수행하십시오.
tmpfile=$(mktemp)
trap 'rm -f "$tmpfile"' EXIT # delete temporary file upon exiting
tr -s ' ' '\n' < "${1:-/dev/stdin}" > "$tmpfile" # convert into word list
sort -u "$tmpfile" | while IFS= read -r word
do
grep -F -o -e "$word" "$tmpfile"
done | awk '{ c[$0]++; if (c[$0] > c[w]) w = $0 } END { print w }'
단어 목록을 정렬하면 고유한 단어 목록이 얻어지므로 어떤 단어도 여러 번 계산되지 않습니다.
이 코드는 최대 하나의 입력 파일이 있다고 명시적으로 가정합니다(그러나 파일이 없을 수 있습니다. 즉, stdin에서 읽음). 이는 질문의 표현과 일치합니다. 그러나 입력 파일이 여러 개 있을 경우(0, 1,이상), tr
행을 다음으로 변경하십시오.
cat -- "$@" | tr -s ' ' '\n' > "$tmpfile" # convert into word list
틀림없이 UUOC이지만
- 두 개 이상의 입력 파일의 경우를 처리합니다.
- 보다 더 읽기 쉽습니다
< "${1:-/dev/stdin}"
.