저는 bash 스크립트를 사용하여 Git 후크를 생성하고 있습니다. 제출한 파일에 대해 프로세스(린팅)를 실행하고 싶습니다. 파일이 실제로 존재하는 경우에만 프로세스를 실행하고 싶습니다. 즉, 커밋에서 삭제된 파일은 고려되지 않습니다. 나는 이것을 시도했다
CHANGED_FILES=$(git diff --cached --name-only | grep ".js$")
echo "$CHANGED_FILES"
if [ -n "$CHANGED_FILES" ]; then
REAL_FILES=()
for pathname in "${CHANGED_FILES[@]}"; do
if [ -e "$pathname" ]; then
REAL_FILES+=( "$pathname" )
fi
done
echo "real files are ..."
echo "$REAL_FILES"
그러나 위의 방법은 단일 파일이 변경된 경우에만 작동합니다. 두 개 이상의 파일이 변경되면 아무 일도 일어나지 않으며 내 출력은 다음과 같습니다.
src/app/test1.js
src/app/test2.js
real files are ...
따라서 CHANGED_FILES 배열에 실제로 존재하는 파일이 2개 이상 포함되어 있으면 "REAL_FILES"에 대해 아무것도 저장되지 않습니다.
위의 문제를 어떻게 해결할 수 있나요?
답변1
스크립트의 문제는 CHANGED_FILES가 배열이 아닌 스칼라 변수라는 것입니다.
노력하다:
CHANGED_FILES=( $(git diff --cached --name-only | grep ".js$") )
즉, 명령 대체 주위에 괄호를 추가하십시오 $(git...)
.
이는 일반적인 쉘 단어 분할의 영향을 받으므로 경로 이름에 공백/줄 바꿈/쉘 메타 문자가 있을 가능성(*)이 있는 경우 다음을 사용해야 합니다 mapfile
.프로세스 교체바꾸다명령 대체, 선택적으로 및 NUL 구분 기호를 모두 사용합니다 -z
. 예를 들어:git diff
grep
mapfile -d '' -t CHANGED_FILES < \
<(git diff -z --cached --name-only | grep -z '\.js$')
그건 그렇고, mapfile
그리고 readarray
는 bash에서 동의어입니다. 자세한 내용은 참조하세요 help mapfile
. 에는 ksh
및 readarray
만 mapfile
존재하지 않습니다.
(*) 가지다언제나이러한 문자는 UNIX 파일 시스템에서 유효한 파일 이름 문자이기 때문에 이렇게 할 가능성이 있습니다. 경로 이름에 있는 유일한 유효하지 않은 문자는 NUL입니다(경로 이름의 파일 이름 부분에 있는 유일한 유효하지 않은 문자는 /
및 NUL입니다). 그러므로 어딘가에 그런 불쾌한 파일 이름이 항상 하나 이상 있을 것이라는 가정을 하고 항상 방어적으로 스크립트를 작성해야 합니다. 즉, 이 mapfile
버전이 항상 사용됩니다.
그건 그렇고, $REAL_FILES 배열의 모든 요소(첫 번째 요소뿐만 아니라)를 인쇄하려면 [@]
아래 첨자를 사용하거나 declare -p
/를 사용하십시오 typeset -p
(이것은 디버깅에 더 적합합니다. 그리고 /를 인용하지 않고 bash에서 실행할 수 있는 무언가를 생성합니다). 출력) 빈 질문).
예를 들면 다음과 같습니다.
echo "$REAL_FILES"
이 작업을 수행:
echo "${REAL_FILES[@]}"
아니면 이거:
typeset -p REAL_FILES
( declare
vs는 typeset
또 다른 차이점입니다 bash
. ksh
ksh에는 readarray
bash가 있고 typeset
bash는 ksh에서 복사하여 이름을 바꾸고 mapfile
ksh declare
버전을 별칭으로 추가합니다. 이유를 모르겠습니다)
답변2
echo "$REAL_FILES"
배열을 문자열로 연결할 필요는 없습니다 .
echo "${REAL_FILES[*]}"
또는 각 요소를 인쇄할 수 있습니다.
printf "%s\n" "${REAL_FILES[@]}"