for 루프의 명령 대체가 작동하지 않습니다.

for 루프의 명령 대체가 작동하지 않습니다.

모든 파일을 보관하고 싶습니다.아니요다음으로 끝나는.bat

나는 노력했다

for f in $(ls | egrep -v .bat); do echo $f; done

그리고

for f in $(eval ls | egrep -v .bat); do echo $f; done

그러나 두 방법 모두 모든 내용을 인쇄하므로 동일한 결과를 생성합니다. 루프 외부에서 사용하면 자체적 ls | egrep -v .bat으로 eval ls | egrep -v .bat작동할 수 있습니다 for.

편집하다

흥미롭게도 해당 플래그를 생략하면 -v루프는 예상된 작업을 수행하고 로 시작하는 모든 항목을 나열합니다 .bat.


질문이 무엇인지 잘 모르겠으므로 질문 제목을 자유롭게 편집하십시오.

나는 그것을 사용하고 있다GNU bash, version 4.1.10(4)-release (i686-pc-cygwin).


$ ls -l | egrep -v ".bat"
total 60K
-rwx------+ 1 SYSTEM SYSTEM 5.3K Jun  6 20:31 fsc*
-rwx------+ 1 SYSTEM SYSTEM 5.3K Jun  6 20:31 scala*
-rwx------+ 1 SYSTEM SYSTEM 5.3K Jun  6 20:31 scalac*
-rwx------+ 1 SYSTEM SYSTEM 5.3K Jun  6 20:31 scaladoc*
-rwx------+ 1 SYSTEM SYSTEM 5.3K Jun  6 20:31 scalap*

명령이 실행 중이지만 for 루프 내에 있지 않습니다.

$ for f in $(ls | egrep -v .bat); do echo $f; done
fsc
fsc.bat
scala
scala.bat
scalac
scalac.bat
scaladoc
scaladoc.bat
scalap
scalap.bat
scalac
scalac.bat
scaladoc
scaladoc.bat
scalap
scalap.bat

디버그 $ set -x

mike@pc /cygdrive/c/Program Files (x86)/scala/bin
$ for f in $(ls | egrep -v .bat); do echo $f; done
++ ls -hF --color=tty
++ egrep --color=auto -v .bat
+ for f in '$(ls | egrep -v .bat)'
+ echo fsc
fsc
+ for f in '$(ls | egrep -v .bat)'
+ echo fsc.bat
fsc.bat
// and so on

답변1

코드에 몇 가지 오류가 있습니다.

$(...)설정 없이 인용되지 않은 명령 대체( ) 사용$IFS

분할+글로브 연산자는 따옴표 없이 확장됩니다. 기본값은 공백, 탭 및 줄 바꿈으로 분할하는 것입니다. 여기서는 개행 문자로만 분할하려고 하므로 IFS를 해당 값으로 설정해야 합니다. 그렇지 않으면 파일 이름에 공백이나 탭이 포함되어 있으면 작동하지 않습니다.

따옴표 없이 명령 대체를 사용합니다 set -f.

분할+글로브 연산자는 따옴표 없이 확장됩니다. 여기서는 와일드카드가 필요하지 않습니다. 즉, 와일드카드를 scala*일치하는 파일 목록으로 확장하는 것입니다. 쉘이 글로빙을 수행하지 않도록 하려면 다음을 사용하여 쉘을 비활성화해야 합니다.set -f

ls별명ls -F

ls위의 문제는 별칭을 사용 했다는 사실로 인해 더욱 악화됩니다 ls -F. /디렉터리 및 *실행 파일 에 추가됩니다 . 따라서 일반적으로 scala실행 파일 ls -F이고 scala*글로빙 패턴이므로 해당 파일로 시작하는 모든 파일 이름으로 확장됩니다. scala이는 egrep -v파일을 필터링하지 않는 것처럼 보이는 이유를 설명합니다.

파일 이름에 개행 문자가 포함되어 있지 않다고 가정합니다.

개행 문자는 파일 이름의 모든 문자만큼 유효합니다. 그래서ls일반적으로 작동하지 않는 출력 구문 분석. 예를 들어, 이라는 파일이 포함된 디렉터리의 출력은 및 ls이라는 a파일이 b포함된 디렉터리의 출력과 동일합니다 a\nb.

위의 내용은 egrep파일 이름이 아닌 파일 이름에 대한 행을 필터링합니다.

egrep대신 사용grep -E

egrep더 이상 사용되지 않습니다. grep -E표준 등가값입니다.

.정규식 연산자를 이스케이프 처리하지 마세요 .

위에서 egrep활성화 했습니다.확장하다정규식이지만 확장된 RE 관련 연산자를 사용하지 않습니다. 당신이 사용하는 유일한 RE 연산자는 .원하는 문자처럼 보이지는 않지만 모든 문자를 일치시키는 것입니다. 그래서 당신 grep -F도 이것을 사용했을 수도 있습니다 . 또는 grep -v '\.bat'.

정규식을 줄 끝에 고정하지 마세요.

egrep .bat뒤에 문자가 포함된 모든 줄과 일치하므로 bat이 정규식은 bat첫 번째 위치에 포함되지 않은 모든 항목을 의미합니다. 그랬어야 했어 grep -v '\.bat$'.

$f인용없이

따옴표가 없는 확장은 분할+글로브 연산자입니다. 여기서는 둘 다 원하지 않으므로 $f따옴표( )로 묶어야 합니다 "$f".

사용echo

echo인수에서 ANSI C 이스케이프 시퀀스를 확장하거나 구현 (및/또는 환경) -n에 따라 특별히 문자열을 처리합니다 .-eecho

printf대신 사용.

따라서 더 나은 솔루션은 다음과 같습니다.

for f in *; do
  case $f in
    (*.bat);;
    (*) printf '%s\n' "$f"
  esac
done

그러나 현재 디렉터리에 숨겨지지 않은 파일이 없으면 출력은 여전히 ​​출력됩니다 . 로 변경하거나 를 실행하여 *문제를 해결할 수 있습니다 .zsh**(N)bashshopt -s nullglob

답변2

이런 식으로 파일을 구문 분석 하면 안 됩니다 ls.

먼저 extglob globstar를 설정한 shopt -s extglob globstar다음

for f in !(*.bat)
  do
   printf '%s\n' "$f"
  done

사용find

find . -type f ! -name '*.bat' 

파일을 보다 안전하게 처리하려면 부정 연산자를 사용하세요.

답변3

for 루프에는 본질적으로 잘못된 것이 없습니다.

$ for f in $(ls | egrep -v .bat); do echo $f; done

위 명령에 대한 결과는 다음과 같습니다.

$ for f in $(ls | egrep -v .bat); do echo $f; done
fsc
scala
scalac
scaladoc
scalap

가능한 수정

한 가지 제안은 다음과 같이 매개변수를 인용하는 것입니다 egrep.

$ for f in $(ls | egrep -v '.bat'); do echo $f; done

Bash에서 스크립트를 작성할 때 발생할 수 있는 다른 잠재적인 문제에 대해서는 Bash Pitfalls 위키를 확인하실 수도 있습니다. 특히 그런 소리가 난다면가장 합리적인 이유왜 이 문제가 발생합니까? 반환된 파일에 공백이 포함되어 있는지 확인하세요.

디버그

시도해 볼 또 다른 방법은 bash 명령을 실행하기 전에 자세한 디버깅을 활성화하여 뒤에서 무슨 일이 일어나고 있는지 확인하는 것입니다.

이렇게 하면 디버깅이 가능해집니다.

$ set -x

그런 다음 명령을 실행합니다.

$ for f in $(ls | egrep -v .bat); do echo $f; done
++ ls --color=auto
++ egrep --color=auto -v .bat
+ for f in '$(ls | egrep -v .bat)'
+ echo fsc
fsc
+ for f in '$(ls | egrep -v .bat)'
+ echo scala
scala
+ for f in '$(ls | egrep -v .bat)'
+ echo scalac
scalac
+ for f in '$(ls | egrep -v .bat)'
+ echo scaladoc
scaladoc
+ for f in '$(ls | egrep -v .bat)'
+ echo scalap
scalap

그런 다음 비활성화하십시오.

$ set +x

CYGWIN 질문이 있으신가요?

bash이러한 예제가 많은 기본 Linux 시스템에서 잘 실행된다는 점을 고려하면 문제는 Cygwin 및/또는 해당 특정 버전 과 관련이 있을 가능성이 높습니다 egrep. $IFSWindows( )와 Unix( )의 다양한 줄 구분 기호에 문제가 있는지 확인하기 위해 Bash의 필드 구분 기호에 특별한 주의를 기울일 것입니다 .0x0d,0x0a0x0a

저는 Cygwin을 설치하지 않았으므로 이 가설을 증명할 방법이 없습니다.

관련 정보