제목의 문제를 해결해야 하는 다음 스크립트가 있지만 키에 값을 할당할 수 없는 것 같습니다. 원인이 예상치 못한 오류였나요? 아니면 스크립트의 주요 버그였나요?
폴더 이름은 gem 파일의 이름입니다. 예를 들어gem-file-foo-1.2.3
이 예에서 키는 버전 번호여야 하며, 동일한 gem의 여러 버전이 있는 경우 gem-file-foo
값은 버전 번호 또는 여러 버전 번호의 문자열이어야 합니다.1.2.3
어떤 키도 출력되지 않습니다 echo "${!my_gems[@]}"
...왜 안 돼?
#!/bin/bash
directory=$GEM_HOME/gems
declare -A my_gems
get_gemset_versions () {
last_key=""
values=""
FIND_RESULTS=$(find $directory -maxdepth 1 -type d -regextype posix-extended -regex "^${directory}\/[a-zA-Z0-9]+([-_]?[a-zA-Z0-9]+)*-[0-9]{1,3}(.[0-9]{1,3}){,3}\$")
printf "%s\n" $FIND_RESULTS | sort |
while read -r line; do
line=${line##*/}
KEY="${line%-*}"
VALUE="${line##*-}"
if [[ $last_key -eq "" ]]; then
last_key=$KEY
fi
if [[ $last_key -eq $KEY ]]; then
values="$values ${VALUE}"
else
values="${VALUE}"
last_key=$KEY
fi
my_gems[$KEY]=$values
done
echo "${!my_gems[@]}"
}
get_gemset_versions
$last_key
또한 $key
동일한 보석 팩을 요약하는 논리도 잘못된 것 같습니다. 이것이 반드시 질문의 일부는 아니지만 여기에 잘못된 논리를 적용하고 있는지 지적해 주시면 감사하겠습니다.
감사해요
답변1
당신은:
printf "%s\n" $FIND_RESULTS | sort |
while read -r line; do
...
done
echo "${!my_gems[@]}"
echo
들여쓰기에 관계없이 파이프 외부에 있습니다 . 기본적으로 Bash는 파이프라인의 모든 부분을 하위 셸에서 실행하므로 파이프라인이 끝난 후에는 루프 내의 할당이 while
표시되지 않습니다. Shellcheck.net은 이에 대해 경고합니다:
Line 32:
my_gems[$KEY]=$values
^-- SC2030: Modification of my_gems is local (to subshell caused by pipeline).
불행히도 해결 방법을 제공하지 않습니다.
Bash에서는 이 lastpipe
옵션을 활성화하거나 프로세스 대체를 사용하여 파이프를 교체할 수 있습니다.
shopt -s lastpipe
echo test | while read line; do
out=$line
done
echo "out=$out"
또는
while read line; do
out=$line
done < <(echo test)
echo "out=$out"
( lastpipe
대화형 쉘에서 시도할 경우 작업 제어와 관련되어 작동하지 않을 수 있습니다.아니요활성화. )
바라보다:내 변수가 하나의 "읽는 동안" 루프에서는 로컬이지만 겉보기에 유사한 다른 루프에서는 로컬이 아닌 이유는 무엇입니까?
어쨌든 이건 좀 이상해 보입니다.
FIND_RESULTS=$(find ...)
printf "%s\n" $FIND_RESULTS
find
줄 바꿈으로 구분된 파일 이름을 출력합니다. 파일 이름에 파일 이름이 포함되어 있지 않다는 것을 알고 있는 한 괜찮습니다. 그러나 여기서 변수의 라운드트립과 인용되지 않은 확장의 단어 분할은 모든 파일 이름을 공백으로 분할합니다.
그냥 실행하세요 find ... | while ...
. 또는 while ...; done < <(find...)
.
또한 선행 및 후행 공백이 깨지는 것을 while IFS= read -r line; do
방지하기 위해 거의 항상 를 사용하고 싶어한다는 점에 유의하십시오 . read
글쎄요, 당신의 파일 이름에도 그런 내용이 포함되지 않기를 바랍니다.
지금은 좋은 참조 질문을 찾을 수 없지만 이는 IFS
공백 포함에만 해당됩니다. 다른 선행 및 후행 구분 기호는 read
하나의 필드만 사용하여 제거되지 않습니다. 예를 들어, IFS=": " read -r foo <<< "::foobar "
휴가(leave)는 foo
문자 그대로 를 의미합니다 ::foobar
. 콜론은 유지되지만 후행 공백은 사라집니다.