폴더에 특정 유형의 파일이 있는지 확인

폴더에 특정 유형의 파일이 있는지 확인

파일 확장자가 .java인지 확인하는 방법은 무엇입니까?

지금까지 나는 다음을 가지고 있습니다 :

  for javaFile in *.java ; do
    {
        echo "The file $javaFile has : " >> ~/Desktop/externalServers.txt
        grep -E '^[^/]{2}.*http' $javaFile >> ~/Desktop/externalServers.txt     

        grep -E '^[^/]{2}.*ftp' $javaFile  >> ~/Desktop/externalServers.txt

        echo "----------------------------------------" >> ~/Desktop/externalServers.txt
        sed -e "s/[[:space:]]\+/ /g" ~/Desktop/externalServers.txt >> ~/Desktop/externalServersTemp.txt
        rm ~/Desktop/externalServers.txt
        mv ~/Desktop/externalServersTemp.txt ~/Desktop/externalServers.txt
        sed 's/^\n//' ~/Desktop/externalServers.txt >> ~/Desktop/externalServersTemp.txt
        rm ~/Desktop/externalServers.txt
        mv ~/Desktop/externalServersTemp.txt ~/Desktop/externalServers.txt

    } done

하지만 이 작업을 수행할 때마다 다음과 같은 오류가 발생합니다.

grep: *.java: 해당 파일이나 디렉터리가 없습니다.

기본적으로 먼저 폴더에 .java 유형 파일이 있는지 확인한 다음 스크립트 실행을 계속 진행하고 싶습니다.

답변1

Bash에서는 다음을 사용하십시오.

shopt -s nullglob
for pdfFile in *.java;do
    # your code goes here
done

이 구문은 Bourne과 같은 쉘에서 작동합니다. 이 nullglob옵션은 bash에만 적용됩니다. 사용한 중괄호( )는 {}C 스타일 쉘용입니다.

shopt -s nullglobnullglob옵션이 설정되면 기본적으로 일치하지 않는 glob을 빈 문자열로 확장해야 한다고 Bash에 알립니다. 기본적으로 *.java일치하는 항목을 찾을 수 없으면 자체적으로 확장됩니다(별표는 유지됨).

답변2

내가 작성한 스크립트는 다음과 같습니다.

set -- *.java
test -e "$1" && {
    fortyequals=$(printf '%040d\n' | tr 0 \=)
    for javaFile do
        printf '%s\nIn file: %s\n%s\n' \
            $fortyequals "$javaFile" $fortyequals
        grep -E '^[^/]{2}.*(ftp|http)' "$javaFile"       
    done 
} >>~/Desktop/externalservers.txt

이미 제공된 솔루션은 다음과 같습니다.불필요하게쉘 특정. 이식 가능한 구문을 사용하면 동일한 효과를 얻을 수 있습니다. 이렇게 하면 장기적으로 기억하기가 덜하고 더욱 강력해진다는 추가 이점이 있습니다. 예:

set -- *.java
test -e "$1" &&
    for javaFile do
#       ...iterate on $javaFile here...
    done

$javaFile또 다른 장점은 다음 루프의 최신 값을 유지할 뿐만 아니라모두$javaFile우리가 한때 가졌던 가치 $@. 이를 통해 다음이 가능해집니다.

...
done

echo "The previous for loop processed $# files."

echo "The first file processed was:"
printf "///\t'%s'\t///\n" "$1"

echo "The last file processed was:"
printf "///\t'%s'\t///\n" "$javaFile"

echo 'All files processed in the for loop were:'
printf "///\t'%s'\t///\n" "$@"

{곱슬머리를 정말 좋아한다면 , 곱슬 }머리에도 사용할 수 있습니다.bash (꼭 필요한 것은 아니지만)- 하지만 두 껍질을 분리해야 합니다.예약어 }그리고 done좋아해요:

for ... do {
...
} ; done

내 제안은 블록 전체를 울타리로 막는 것입니다.에 대한루프 for및 수행하는 모든 후처리 - 공상적으로는 다음에 따라 다릅니다.&& 예약어좋다:

set -- *.java
test -e "$1" && {
    for ... done
#   ...further processing on $@...
} 

돌이켜보면 정규식으로도 큰 도움이 될 수 있었을 거라 생각합니다... 다음 단어가 포함된 행을 찾고 있는 것 같습니다.http그리고/또는파일 전송 프로토콜그렇게아니요두 개로 시작하다//.

나머지는 혼자 하는 일이라고 생각해요 grep. 빈 줄을 지우려고 하는 것 같지만, 내가 상상하는 것처럼 이러한 빈 줄은 처음에 파일에 반복적으로 추가된 결과일 뿐입니다.

따라서 for루프의 출력을 출력 파일에 직접 쓸 수 있으므로 ~/Desktop/externalservers.txt루프가 완료될 때까지 쓰기 설명자가 유지되므로 빈 줄을 쓰지 않아도 됩니다. 아마도 다음과 같습니다:

for ... done >>outfile

또는

{ grouped ; command ; list ; } >>outfile

적어도 이 문장이 원하는 효과를 얻지 못할 수도 있다는 점은 말씀드릴 수 있습니다.

sed 's/^\n//' $file

sedewline으로 구분 됩니다 . 줄의 첫 번째 문자 로 ewline을 \n만날 수 없습니다 . 다양한 방법으로 패턴 공간 에 줄눈을 넣을 수 있지만 , 일부 처리 없이는 절대 넣을 수 없습니다.\n^\nsed

답변3

샘플 코드의 또 다른 문제는 일반적으로 원하는 것입니다.모든 반복자에 큰따옴표를 사용하세요.for 루프에서 사용할 때.

귀하의 코드:

for javaFile in *.java ;
    {
        echo "The file $javaFile has : " >> ~/Desktop/externalServers.txt
        grep -E '^[^/]{2}.*http' $javaFile >> ~/Desktop/externalServers.txt     

        grep -E '^[^/]{2}.*ftp' $javaFile  >> ~/Desktop/externalServers.txt

해야 한다:

for javaFile in *.java ; do
        echo "The file $javaFile has : " >> ~/Desktop/externalServers.txt
        grep -E '^[^/]{2}.*http' "$javaFile" >> ~/Desktop/externalServers.txt

        grep -E '^[^/]{2}.*ftp' "$javaFile"  >> ~/Desktop/externalServers.txt

답변4

Joseph의 nullglob방법이 가장 우아하지만, 이를 사용하고 싶지 않거나 사용할 수 없는 경우(예: bash가 아닌 쉘 또는 이전 bash 버전) 이 작업을 수행할 수도 있습니다(파일 이름에 개행 문자가 포함되어 있지 않다고 가정).

file="~/Desktop/externalServers.txt"
while IFS= read -r javaFile
do
  echo "The file $javaFile has : " >> "$file"
  grep -E '^[^/]{2}.*http' "$javaFile" >> "$file"
  grep -E '^[^/]{2}.*ftp' "$javaFile"  >> "$file"

  echo "----------------------------------------" >> "$file"
  ## The -i flag enables in-place editing so you don't need
  ## to fiddle about with temp files.
  sed -i -e "s/[[:space:]]\+/ /g" "$file"
  sed -i -n '/[^[:space:]]/p' "$file"
done < <(find . -maxdepth 1 -name '*.java')

공백이 포함된 파일 이름을 적절하게 처리할 수 있도록 입력 필드 구분 기호를 비워 두십시오 IFS=. 옵션은 백슬래시를 특별히 처리하지 않음을 -r나타냅니다 read(파일 이름에 백슬래시가 포함될 수 있는 경우). 이 <(command)구조는프로세스 교체그리고 한 명령의 출력을 다른 명령의 입력으로 전달하는 방법입니다.

$file출력 파일 이름을 변경하려는 경우 모든 줄을 편집할 필요가 없도록 이 변수를 도입했습니다 .

나는 -ised 플래그를 사용했는데, 이를 통해 원본 파일을 편집할 수 있고 임시 파일이 필요하지 않습니다. 또한 이 작업을 수행할 이유가 없으며 rm foo.txt; mv bar.txt foo.txt언제든지 수행할 수 mv bar.txt foo.txt있으며 대상 파일을 덮어쓰게 됩니다. 이제 이 명령이 무엇을 해야 할지 모르겠습니다.

sed 's/^\n//' ~/Desktop/externalServers.txt >> ~/Desktop/externalServersTemp.txt

빈 줄을 제거하고 싶었지만 작동하지 않아서 위에서 변경했습니다.

sed -i -n '/[^[:space:]]/p' ~/Desktop/externalServers.txt

-n모든 줄을 인쇄하는 sed의 기본 동작을 억제합니다 . /[^[:space:]]/이는 공백이 아닌 문자와 일치하는 모든 줄과 일치하며 p끝에 's'는 해당 줄과 해당 줄만 인쇄됨을 의미합니다. 이것이 명령으로 수행하려는 작업이 아닌 경우 sed알려주시면 필요에 따라 편집하겠습니다.

관련 정보