Bash: "if"와 "find"를 함께 사용하여 폴더의 파일을 확인하세요.

Bash: "if"와 "find"를 함께 사용하여 폴더의 파일을 확인하세요.

일련의 "histogram_0000_0000" 폴더가 포함된 상위 폴더가 있습니다. 모든 폴더에서 "out.txt" 파일을 검색하고 폴더에서 파일이 발견될 때마다 이를 반환하는 bash 스크립트를 만들려고 합니다(파일이 모든 폴더에 있는지 확인하기 위해). 내가 얻은 스크립트는 다음과 같습니다.

#!/bin/bash
joblist='job_list.txt'
njobs=`wc ${joblist} | awk '{print $1}'`

cwd=`pwd`
for ((i=1 ; i <= ${njobs} ; i++ )); do
        folder=`awk '(NR=='${i}'){print}' ${joblist}`
        echo $folder
        cd ${folder}
        if [ find -name "out.txt" ]
        then
                echo out.txt found in $folder
        fi
        cd ${cwd}
done

하지만 실행할 때마다 오류가 발생합니다.

./checkrun.sh: 10행: [: -name: 이진 연산자 필요

주위를 둘러보고 "[[" 및 "]]"를 사용해 보았지만 여전히 왜 운이 좋은지 모르겠습니다! 어떤 도움이라도 좋을 것입니다. 고마워요, -잭

답변1

[... ]문자열 또는 숫자 표현식을 테스트합니다. 명령이 일치하는지 확인하려면 find출력(비어 있지 않은 문자열, 를 사용하여 테스트 -n)을 제공하는지 테스트해야 합니다.

if [[ -n "$(find -name 'out.txt')" ]]
then
    echo "out.txt found in $folder"
fi

$(...)명령의 출력을 캡처하기 위해 더 이상 사용되지 않는 역따옴표 대신 최신 구문을 사용하고 있습니다 `...`.

다른 제안,

  • 행 수를 얻기 njobs=위해 wc ${joblist} | awk '{print $1}'``를 단순화할 수 있습니다 .njobs=$(wc -l <"$joblist")

  • $iawk변수 로 전달되었으며,folder=$(awk -v i="$i" 'NR==i {print}' "$joblist}")

  • cd하위 폴더로 이동한 다음 를 사용하여 cd원래 위치로 돌아가지 마십시오 . 하위 디렉터리를 참조하려면 상대 경로를 사용하고, cd제한된 컨텍스트에서 하위 디렉터리를 유지하려면 하위 쉘을 사용하세요. 여기서는 첫 번째 방법을 사용합니다.

      echo "$folder"
      if [[ -n "$(find "$folder" -name 'out.txt')" ]]
      then
          echo "out.txt found in $folder"
      fi
    
  • 항상 상대 경로인 경우 $folder경로로 사용되는 곳마다 "./$folder"로 참조됩니다. 이렇게 하면 -대시( )로 시작하여 대시( )를 일련의 옵션으로 해석하려는 명령에 혼동을 줄 수 있습니다.

  • 쉘에는 bash이미 현재 작업 디렉토리에 대한 변수가 있으므로 다음 cwd=`pwd`과 같이 단순화할 수 있습니다.cwd="$PWD"

  • 사용https://shellcheck.net/코드를 확인하세요. (프라이빗 코드 공유가 걱정된다면 로컬에 설치해도 됩니다.)

답변2

#!/bin/bash
joblist='job_list.txt'
njobs=`wc ${joblist} | awk '{print $1}'`

cwd=`pwd`
while IFS= read -r line
do
        folder="$line"   #`awk '(NR=='${i}'){print}' ${joblist}`
        echo $folder
        cd ${folder}
        if [ -f out.txt ]
        then
                echo out.txt found in $folder
        fi
        cd ${cwd}
done < job_list.txt

이게 도움이 되길 바란다. 조금 더 쉽습니다... line=current-line-from'job_list.txt' 한 줄씩 읽으므로 파일은 다음과 같습니다.

folder1
folder2
folder234

내 결과:

france1@macubuntu:/tmp/tmdf$ bash script.sh 
folder1
folder2
folder234
out.txt found in folder234
france1@macubuntu:/tmp/tmdf$ 

제가 도움이 되었기를 바랍니다...

답변3

zsh대신 이것을 사용하겠습니다 bash.

#! /bin/zsh -
joblist='job_list.txt'
dirs=( ${(f)"$(<$joblist)"} )

for dir in $dirs; do
  first_out=( $dir/**/out.txt(NDY1) )
  if (( $#first_out )); then
    print -r out.txt found in $dir
  fi
done

bash다른 GNU의 경우에는 find다음과 같습니다.

#! /bin/bash -
joblist='job_list.txt'

dirs=(); readarray -t dirs < "$joblist"

for dir in "${dirs[@]}"; do
  [[ -n $dir ]] || continue
  [[ $dir = [/.]* ]] || dir=./$dir

  first_out=$(find "$dir" -name out.txt -print -quit)

  if [[ -n $first_out ]]; then
    printf '%s\n' "out.txt found in $dir"
  fi
done

몇 가지 참고사항:

  • readarray -t lines < file파일의 행을 배열로 저장하는 것도 가능하지만, file열 수 없는 경우에는 readarray실행조차 되지 않아 $dirs설정도 되지 않으므로 미리 변수를 초기화하는 것이 중요하다는 점에 유의하세요.
  • bash마지막으로 **/zsh 스타일 재귀 와일드카드( ) 옵션에 대한 지원이 추가되었습니다 globstar. 그러나 여전히 심볼릭 링크 처리(버전 간 동작 변경)와 관련된 몇 가지 문제가 있으며, 더 중요한 것은 이 경우 사용된 목록을 정렬하지 않고도 for N, nullglobfor D또는 첫 번째 일치 시 dotglob중지 와 같은 glob 한정자에 대한 지원을 추가하지 않는다는 것입니다. Y1위에.
  • findfind "$dir"로 시작 하면 $dir중단됩니다 -. 옵션 끝 표시 find에 대한 지원이 실제로 지원되지만 , 로 시작하는 인수는 옵션이 아닌 경우(예: , 또는 ) 여전히 조건자로 처리되기 때문에 여기서는 도움이 되지 않습니다. 그렇기 때문에 절대값 이 아니고 아직 시작하지 않는 s를 앞에 붙이는 것입니다 (그래서 가 됩니다 ). BSD는 이 문제 방지를 지원 하지만 GNU는 아직 지원하지 않습니다 .---()!./$dir.-my-annoying-dir-./-my-annoying-dir-findfind -f "$dir"find
  • 최소한 하나라도 존재하는지 확인하려는 경우에는 out.txt모두 찾을 필요가 없습니다 . 첫 번째 게임에서 멈출 수 있습니다. 따라서 (GNU에 따라) -quit(일부 BSD에는 -exit이에 대한 규정이 있습니다).
  • zsh는 ${(f)"$(<file)"}개행으로 분할되지만 따옴표가 없으면 빈 요소가 제거됩니다(그렇지 않은 경우 $dirs아래에서 따옴표가 없는 다음 요소가 해당 요소를 제거합니다). 빈 경로는 일반적으로 유효한 경로가 아니므로 오류가 발생해야 하지만 와 연결되면 /something성가시게도 유효할 수 있는 관련 없는 절대 경로로 변합니다. 앞에 오면 ./현재 디렉토리가 됩니다. 따라서 여기서는 건너뛰는 것이 더 낫습니다. 따라서 [[ -n $dir ]] || continuebash 변형입니다.

관련 정보