저는 주어진 텍스트 파일을 가져와 문자 수, 모음 수, 각 모음 수를 계산하는 스크립트를 작성 중입니다. 첫 번째 부분은 쉽지만 루프에 문제가 있습니다. 내 이해는 myString 개수가 루프 개수가 된다는 것입니다. 문자를 읽을 때마다 if/elif 문을 거쳐 모음과 일치하면 해당 모음에 해당하는 변수의 값을 1씩 증가시킵니다.
Shellcheck.net은 내 라인을 좋아하지 않지만 그 이유를 이해할 수 없습니다.
#!/bin/bash
myString=$(cat sampletext.txt | tr A-Z a-z) #this works
count=$(echo -n "$myString" |tr -d '[.]'| wc -c) #this works
vowels=$(echo -n $myString | tr -cd 'aeiou'| wc -c) #this works
va=0
ve=0
vi=0
vo=0
vu=0
i=0
while (( i++ < ${#myString} )); do
char=$(expr substr "$myString" "$i" 1)
if [ "$char" -eq "a" ]; then
((va=++))
elif [ "$char" -eq "e" ]; then
((ve=++))
elif [ "$char" -eq "i" ]; then
((vi=++))
elif [ "$char" -eq "o" ]; then
((vo=++))
elif [ "$char" -eq "u" ]; then
((vu=++))
fi
done
echo $vi
쉘 검사 출력:
((va=++))
^-- SC1105 (error): Shells disambiguate (( differently or not at all. For subshell, add spaces around ( . For ((, fix parsing errors.
^-- SC2030 (info): Modification of va is local (to subshell caused by (..) group).
*안타깝지만, 안되는 부분만 넣었습니다. Shebang을 포함한 전체 내용을 표시하도록 편집했습니다 =)
답변1
awk
기본적인 솔루션을 제공할 예정입니다 .당신이 언급한당신이 원해요"내가 만들고 싶은 보고서를 작성하기 위해 루프를 사용하는 방법을 배우고 이해합니다."awk
, 이는 일반적으로 순수보다 이 경우 더 효율적입니다.bash
#!/bin/sh
#
grep -o -- . "$1" |
awk '
/[[:alpha:]]/ { letters[tolower($1)]++ }
/[aeiou]/ { vowels++ }
END {
printf "%d\tvowels\n", vowels;
for (letter in letters) {
printf "%d\t%s\n", letters[letter], letter | "sort -k2,3"
}
}
'
파일을 호출 letters
하고 실행 가능하게 만듭니다( chmod a+x letters
). 입력 파일이 sampletext.txt
다음과 같이 실행될 수 있습니다
./letters sampletext.txt
노트
grep -o -- . {file}
(GNUgrep
또는 호환 가능하다고 가정) 파일을 한 줄에 하나씩 개별 문자로 분할합니다.awk
내부에서 이 작업을 수행 할 수도 있지만 이는 빠르고 게으른 방법입니다.[[:alpha:]]
알파벳 문자와 일치합니다.[[:alnum:]]
영숫자 또는.
임의의 문자를 사용할 수 있습니다 .- 이
printf | "sort"
구성은 서식이 지정된 모든 출력을 명령(단일 인스턴스)에 공급하고sort
, 명령은 현재 로케일을 기준으로 열 2를 기준으로 정렬합니다.
답변2
Bash에는 디렉토리 목록과 여러 색인(부록 D 참조)이 포함된 190페이지 분량의 매뉴얼이 함께 제공됩니다. (다소 모호하고 무서운) 구문은 많은 기능을 숨깁니다.
여기에 있는 대부분의 답변/튜토리얼은 이러한 부분에 따라 달라집니다.
www.gnu.org/software/bash/manual/bash.html#Arrays
www.gnu.org/software/bash/manual/bash.html#Shell-Parameter-Expansion
배열에는 특별한 것이 없습니다. 배열은 변수 집합에 대해 유사한 이름을 많이 만들어내는 것을 피하는 게으른 사람의 방법일 뿐입니다. 인덱스 값을 이름의 마지막 부분으로 처리합니다. 그러나 인덱스 자체는 변수이기 때문에 루프를 위한 훌륭한 도구입니다.
다음은 의도를 나타내는 충분한 설명이 포함된 스크립트입니다.
#! /bin/bash
myString="The quick brown FOX jumps over the lazy dog."
Vowel=( a e i o u ) #.. Declare a list of what we want to output.
myString="${myString,,}" #.. Shell substitution to lowercase a string.
#.. Declares an associative array to store character frequencies.
#.. Typical values would be: Freq[e]="3", Freq[h]="2", Freq[q]="1".
#.. We store counts for all characters, to avoid multiple tests.
declare -A Freq
#.. Iterate the string, indexing via a substring expansion,
#.. and counting the frequencies of each ASCII character.
for (( j = 0; j < ${#myString}; j++ )); do
(( Freq[\${myString:j:1}]++ ))
done
declare -p Freq #.. Debug of the frequency array.
#.. Iterate over the vowel list to report the frequencies.
for v in "${Vowel[@]}"; do
printf 'Vowel %s occurs %2d times.\n' "${v}" "${Freq["${v}"]}"
done
출력은 다음과 같습니다.
$ time ./Calhoun.sh
declare -A Freq=([" "]="9" [.]="1"
[a]="1" [b]="1" [c]="1" [d]="1"
[e]="3" [f]="1" [g]="1" [h]="2" [i]="1"
[j]="1" [k]="1" [l]="1" [m]="1" [n]="1"
[o]="4" [p]="1" [q]="1" [r]="2" [s]="1"
[t]="2" [u]="2" [v]="1" [w]="1" [x]="1"
[y]="1" [z]="1" )
Vowel a occurs 1 times.
Vowel e occurs 3 times.
Vowel i occurs 1 times.
Vowel o occurs 4 times.
Vowel u occurs 2 times.
real 0m0.013s
user 0m0.012s
sys 0m0.000s
답변3
myString="Hello WORLD"
declare -A vowel=() # an associative array
declare -l char # value is lowercased upon assignment
for ((i=0; i<${#myString}; i++)); do
char=${myString:i:1}
# inside [[...]], the == operator does _pattern matching_
[[ $char == [aeiou] ]] && ((vowel[$char]++))
done
declare -p vowel # => ([o]="2" [e]="1" )
문자열의 문자를 반복하는 더 효율적인 방법(특히 문자열이 긴 경우)은 다음과 같습니다.
while IFS= read -r -d '' -n1 char; do
[[ $char == [aeiou] ]] && ((vowel[$char]++))
done < <(
printf '%s' "$myString"
)
개수가 0인 모음을 포함하려면 다음을 수행하세요.
myString="Hello WORLD"
declare -A vowel=([a]=0 [e]=0 [i]=0 [o]=0 [u]=0)
declare -l char
while IFS= read -r -d '' -n1 char; do
[[ -v "vowel[$char]" ]] && ((vowel[$char]++))
done < <(printf '%s' "$myString")
for char in "${!vowel[@]}"; do
printf '%s\t%d\n' "$char" "${vowel[$char]}"
done | sort
a 0
e 1
i 0
o 2
u 0```
답변4
awk
각 모음에 대한 순수 솔루션은 개별적으로 제공됩니다.
#define array vowels with one vowel for each index
BEGIN{ split("aeiou",vowels,"") }
#in each line, make line lowercase
{$0=tolower($0)
#for each vowel occurence (loops through array vowels),
#replace vowel with empty string.
#gsub returns the number of replacements is has made,
#this value is added to the counter array element for each vowel
for (letter in vowels) { count[letter]+=gsub(vowels[letter],"") } }
#in the end, loop through array vowels and return vowel and counter value
END { for (letter in vowels) {print vowels[letter],count[letter]} }
예제로 저장 count_vowels.awk
하고 다음을 통해 실행하세요.
awk -f count_vowels.awk inputfile.txt
#
-lines는 주석이므로 생략 가능합니다.