shopt glob 설정이나 tcsh와 유사한 설정 조합이 있습니까?

shopt glob 설정이나 tcsh와 유사한 설정 조합이 있습니까?

오랫동안 tcsh 사용자를 사용하다가 새로운 bash 사용자로 전환하려고 합니다(너무 늦었습니다). 나는 정기적으로 tcsh에서 많은 foreach 루프를 작성하므로 대안으로 bash의 for 루프 구문을 배웠지만 일치하지 않는 glob 패턴이 리터럴 문자열로 루프를 통해 전달되는 것을 보고 놀랐습니다. 리터럴 문자열을 건너뛰고 찾을 수 있도록 이 동작을 변경하는 방법을 찾고 있습니다 shopt -s nullglob. 내 이해는 이론적으로 이것이 tcsh의 작동 방식과 동일해야 한다는 것입니다. 그러나 오늘 나는 차이점을 발견했습니다. 이 작업을 수행하면 ls ../*.doesnotmatch결과는 현재 디렉터리의 내용 목록입니다. 구체적으로는 다음과 같이 합니다.

큰 타격:

$ shopt -s nullglob
$ ls ../*.sam
extractSplitReads_BwaMem    extractSplitReads_BwaMem.xml
$ shopt -u nullglob
$ ls ../*.sam
ls: ../*.sam: No such file or directory

상위 디렉토리의 어떤 것도 일치하지 않으며 *.sam, 특히 현재 디렉토리와 일치합니다. 처음에는 정말 혼란스러웠지만, 전역 모드가 사라지고 인수를 제공하지 않은 것처럼 명령이 실행되고 있다는 것을 깨달았습니다. 예를 들면 다음과 같습니다.

$ ls

그래서 FAILGlob만 설정하고 nullglob을 사용하여 페일글로브를 설정하려고 시도했지만, 페일글로브가 설정되자마자 일치하는 패턴이 있는지 여부에 관계없이 일치하지 않는 glob 패턴이 있으면 명령이 종료됩니다.

큰 타격:

$ shopt -s failglob
$ shopt -s nullglob
$ ls ../vis*/*.xml
../visualization/LAJ.xml
$ ls ../vis*/*.xml ../*.sam
bash: no match: ../*.sam
$ ls ../{vis*/*.xml,*.sam}
bash: no match: ../*.sam

tcsh를 사용하면 모든 glob이 일치하는 항목으로 줄어들고, 일치하는 항목이 없으면 glob 오류가 발생합니다.

tcsh:

$ ls ../vis*/*.xml ../*.sam
../visualization/LAJ.xml
$ ls ../{vis*/*.xml,*.sam}
../visualization/LAJ.xml
$ ls ../*.sam
ls: No match.

나는 shopt 설정을 보았지만 이 동작을 달성하는 방법을 찾을 수 없었습니다. 내가 뭐 놓친 거 없니? Bash나 tcsh 외에 tcsh와 같은 전역 변수를 처리할 수 있는 또 다른 최신 셸이 있습니까? 나는 일치하는 항목이 있을 때 nullglob 동작을 원하지만, 일치하는 항목이 없을 때는 Failglob 동작을 원합니다. 이는 tcsh가 작동하는 방식인 것 같습니다.

답변1

shopt파일 이름 확장자와 관련된 유일한 옵션은 dotglob, failglob및 이며, 그 중 어느 것도(단독으로든 조합으로든) 정확히 원하는 작업을 수행하지 못하는 것 같습니다. 좋은 생각처럼 들리기 때문에 안타깝습니다.nocaseglobnullglob

내 제안은 failglob다음과 같이 필요하지 않은 명령을 피할 수 있도록 대화형 세션에서 설정하는 것입니다.

mv -r file1 file2 dir1 dir2 destination-*-dir

file1, 및가 일치하지 않고 설정된 경우 file2및가 dir1해당 항목으로 이동됩니다.dir2destination-*-dirnullglob

반면에 쉘 스크립트를 작성할 때 파일 이름 확장에만 의존하는 것은 좋은 생각이 아닙니다. 그러한 확장이 존재하는지, 어떤 확장이 있어야 하는지 항상 확인하는 것이 좋습니다.

내 말은, 이러지 마세요:

rm -- *.jpg *.txt

다음과 같이 하는 것이 더 좋습니다:

for file in *.jpg *.txt; do
  if [ -f "${file}" ]; then
    rm -- "${file}"
  fi
done

# Or this (non-POSIX, as it uses an array)

for file in *.jpg *.txt; do
  if [ -f "${file}" ]; then
    files_to_delete+=( "${file}" )
  fi
done

if [ "${#files_to_delete[@]}" -gt 0 ]; then
  rm -- "${files_to_delete[@]}"
fi

이렇게 하면 일부 파일이 일치하더라도 안전 *.txt하지만 실제로는 디렉터리입니다.

관련 정보