grep, sort 및 uniq를 사용하여 세 개의 출력 필드를 만드는 방법

grep, sort 및 uniq를 사용하여 세 개의 출력 필드를 만드는 방법

내 명령에서 두 개의 파일을 사용하고 있는데 첫 번째 파일( file1)은 알파벳의 각 문자가 별도의 줄에 있는 파일입니다. 두 번째 파일( $w내 명령에서)은 거대한 단어 목록입니다. 알파벳 목록과 단어 목록을 비교하여 알파벳 문자를 두 번 포함하는 단어를 찾고, 각 문자에 대한 단어 수와 예제 단어를 표시해야 합니다. 출력은 다음과 같지만 전체 알파벳에 대해

v 94 bivalve
w 94 awkward
x 3 executrix
y 196 abysmally
z 58 bedazzle

아래는 내 명령과 그 결과입니다

 for i in `cat file1`; do grep $i.*$i $w | sort | uniq -c | head -1; done
  1 aardvark    
  1 abba
  1 acacia
  1 abandoned
  1 abalienate
  1 affability
  1 ageing
  1 aforethought
  1 abalienation
  1 hajj
  1 backstroke
  1 abnormally
  1 accommodate
  1 abalienation
  1 abdominous
  1 agitprop
  1 quinqevalent
  1 aardvark
  1 abbess
  1 abatement
  1 absquatulate
  1 bivalve
  1 awkward
  1 executrix
  1 abysmally
  1 bedazzle

답변1

비교적 새로운 버전을 사용한다고 가정하면 bash비슷한 작업을 수행할 수 있습니다.

for CHAR in {a..z}
do
    WORD_LIST=( $(grep "$CHAR.*$CHAR" $w) )
    echo $CHAR ${#WORD_LIST[@]} ${WORD_LIST[0]}
done

우리는 크기 개수를 제공하는 bash 배열을 사용하고 ${#WORD_LIST[@]}있으며 배열의 첫 번째 요소를 가져오고 있습니다 ${WORD_LIST[0]}.

귀하의 예가 작동하지 않는 이유는 uniq -c고유한 인스턴스만 계산하므로 전달된 모든 단어의 수가 아닌 각 단어의 수를 제공하고 첫 번째 출력만 얻을 수 있기 때문입니다.

답변2

Zachary Brady 버전부터 시작:

for i in {a..z} 
 do 
   ( echo $i ;
     grep -c    "^[^$i]*$i[^$i]*$i[^$i]*$" file1; 
     grep -m 1  "^[^$i]*$i[^$i]*$i[^$i]*$" file1
   ) | paste - - - 
 done
  • "^[^$i]*$i[^$i]*$i[^$i]*$"정확히 2번 발생하는지 확인하는 것입니다 $i (예 ^[^a]*a[^a]*a[^a]*$).
  • grep -c ... 일치하는 단어 수를 계산합니다.
  • grep -m 1 ... 첫 번째로 일치하는 단어를 얻습니다.
  • 붙여넣기 - - - ... 3개의 출력 라인을 하나로 병합

임의의 단어 예를 선호하는 경우 두 번째 grep을 다음으로 바꾸십시오.

grep "^[^$i]*$i[^$i]*$i[^$i]*$" file1 | shuf | head -1

"정확히 2개가 있는지 확인"하는 또 다른 옵션은 2 aa를 찾아 aaa인 경우 거부하는 것입니다.

grep 'a.*a' file1  | grep -vc 'a.*a.*a' 

답변3

이를 수행하는 방법에는 두 가지가 있습니다. 하나는 쉘 지향(주로 grep 사용)이고 다른 하나는 awk를 사용하는 것입니다.

w=/usr/share/dict/words
sort file1 | uniq | while read letter
do
  count=$(grep -ic "^[^$letter]*$letter[^$letter]*$letter[^$letter]*$" "$w")
  r=$(( (RANDOM % count) + 1 ))
  printf "%s %d %s\n" "$letter" $count \
    $(grep -i "^[^$letter]*$letter[^$letter]*$letter[^$letter]*$" "$w" | \
        sed -n ${r}p )
done

file1이 지시된 대로(한 줄에 한 글자씩) 준비된 경우 초기 정렬 및 uniq는 필요하지 않지만 "정렬 및 uniq에 grep 사용" 요구 사항에 더 가까워지기 위해 아무 이유 없이 추가했습니다.

이상한 해결책 :

BEGIN {
  split("abcdefghijklmnopqrstuvwxyz", alphabet, "");
  srand();
}
{
  for (i in alphabet) {
    letter=alphabet[i]
    if (match(tolower($1), "^[^"letter"]*"letter"[^"letter"]*"letter"[^"letter"]*$")) {
      counts[letter]++
      if (wordfor[letter]) {
        if (rand() * counts[letter] >= counts[letter] - 1)
          wordfor[letter]=$1
      } else
        wordfor[letter]=$1
    }
  }
}
END {
  for (i in alphabet)
    print alphabet[i], counts[alphabet[i]], wordfor[alphabet[i]]
}

파일에 저장하고 다음과 같이 사용하십시오.

w=/usr/share/dict/words ## or whatever
awk -f theabove.awk "$w" | sort

관련 정보