Bash에서 파일 시스템에 여전히 존재하는 커밋된 파일 배열을 어떻게 생성합니까?

Bash에서 파일 시스템에 여전히 존재하는 커밋된 파일 배열을 어떻게 생성합니까?

저는 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 diffgrep

mapfile -d '' -t CHANGED_FILES < \
  <(git diff -z --cached --name-only | grep -z '\.js$')

그건 그렇고, mapfile그리고 readarray는 bash에서 동의어입니다. 자세한 내용은 참조하세요 help mapfile. 에는 kshreadarraymapfile존재하지 않습니다.

(*) 가지다언제나이러한 문자는 UNIX 파일 시스템에서 유효한 파일 이름 문자이기 때문에 이렇게 할 가능성이 있습니다. 경로 이름에 있는 유일한 유효하지 않은 문자는 NUL입니다(경로 이름의 파일 이름 부분에 있는 유일한 유효하지 않은 문자는 /및 NUL입니다). 그러므로 어딘가에 그런 불쾌한 파일 이름이 항상 하나 이상 있을 것이라는 가정을 하고 항상 방어적으로 스크립트를 작성해야 합니다. 즉, 이 mapfile버전이 항상 사용됩니다.


그건 그렇고, $REAL_FILES 배열의 모든 요소(첫 번째 요소뿐만 아니라)를 인쇄하려면 [@]아래 첨자를 사용하거나 declare -p/를 사용하십시오 typeset -p(이것은 디버깅에 더 적합합니다. 그리고 /를 인용하지 않고 bash에서 실행할 수 있는 무언가를 생성합니다). 출력) 빈 질문).

예를 들면 다음과 같습니다.

echo "$REAL_FILES"

이 작업을 수행:

echo "${REAL_FILES[@]}"

아니면 이거:

typeset -p REAL_FILES

( declarevs는 typeset또 다른 차이점입니다 bash. kshksh에는 readarraybash가 있고 typesetbash는 ksh에서 복사하여 이름을 바꾸고 mapfileksh declare버전을 별칭으로 추가합니다. 이유를 모르겠습니다)

답변2

echo "$REAL_FILES"배열을 문자열로 연결할 필요는 없습니다 .

echo "${REAL_FILES[*]}"

또는 각 요소를 인쇄할 수 있습니다.

printf "%s\n" "${REAL_FILES[@]}"

관련 정보