Linux 쉘 스크립트에서 find 명령을 사용한 조건인 경우

Linux 쉘 스크립트에서 find 명령을 사용한 조건인 경우

if 조건에서 find 명령을 작성하려고 합니다. 먼저 요구 사항을 공유하겠습니다. /tmp/fmxfile이라는 파일에 파일 목록이 있습니다.

cat /tmp/fmxfile
/fmx/eng/hint.fmx
/pll/case.pll
/plx/eng/case.plx

첫 번째 IF 조건에서 먼저 파일 위에 for 루프를 작성하고 있습니다(조건이 통과하면 다른 경로에서 모든 파일 찾기). 파일이 해당 경로에 있는지 두 번째 IF 조건에 없는지 확인하고 싶습니다. 지난 5분 동안 파일이 수정되었는지 확인하고, true인 경우 파일을 /tmp 경로에 복사합니다.

cd /apps/common/bau/base/
for file in `cat /tmp/fmxfileslist`
do
if [ -f $file ]
then
    echo "File '${file}' found in $(pwd) path and created on $(date +%D)."
    if [ $(find $file -mmin -5 -type f) ="true" ];
    then
    cp -a $file /tmp/basefmxfiles
    ls -lrt | grep /tmp/basefmxfiles
    else 
    echo "But the file is not modified in last 5 minutes"
    fi
else
echo "$0: File '${file}' not found."
fi
done

답변1

코드에 대한 몇 가지 설명( sh구문에 있다고 가정):

cd /apps/common/bau/base/

종료 상태를 확인하지 않으므로 cd실패하면 현재 작업 디렉토리에서 나머지 스크립트를 계속 실행합니다.

for file in `cat /tmp/fmxfileslist`

더 이상 사용되지 않는 명령 대체 형식 위에 분할+glob을 사용하며 `...`파일 행을 반복하려는 것처럼 보이지만 구문은 다음과 같습니다.

while IFS= read -r file <&3; do
  ...
done 3< /tmp/fmxfileslist

(또는 변경해야 합니까 /tmp/fmxfile)?

/tmp또한 전역적으로 쓰기 가능한 디렉터리에서 고정된 이름(예:)을 가진 파일을 사용하는 것은 보안 관점에서 나쁜 습관입니다.

또한 예제 목록의 경로 중 어느 것도 상대 경로가 아니므로 현재 작업 디렉터리가 무엇인지가 중요합니까? 또는 목록은 다음과 같아야 합니다.

fmx/eng/hint.fmx
pll/case.pll
plx/eng/case.plx

대신에? 아니면 앞에 선행을 /제거하거나 삽입해야 합니까?.

do
if [ -f $file ]

이것은 확장에서 다시 분할+glob을 사용하는 것인데 $file, 이는 말이 되지 않습니다. 아마도 당신이 의미하는 것은 [ -f "$file" ]파일이 존재하는지 확인하는 것이 목적인지, 파일에 액세스할 수 있고 다음으로 식별될 수 있는지 여부입니다.정기적인(디렉토리, fifo, 장치, 소켓이 아님...) 심볼릭 링크 확인 후.

then
    echo "File '${file}' found in $(pwd) path and created on $(date +%D)."

$(pwd)이번에는 최신 형태의 명령 대체를 사용하여 $PWDPOSIX 쉘에 작성하는 것이 가능합니다. date +%D현재 날짜를 인쇄합니다. $fileGNU를 가정하여 마지막 수정 시간을 인쇄하려면 date이 옵션을 사용할 수 있습니다 -r. %D제공된 날짜 형식은 mm/dd/yy매우 모호하며 시간이나 시간대 정보를 제공하지 않습니다. $(date -r "$file" +%FT%T%z || echo UNKNOWN).

또한 echo임의의 데이터에는 사용할 수 없습니다. 대신 사용하십시오 printf '%s\n' "...".

    if [ $(find $file -mmin -5 -type f) ="true" ];

$file이번에도 sum 의 출력에 Split+glob을 사용하세요 find. 또한 공백이 누락되어 =명령 에 비교 연산자 인수가 [표시되지 않고 =대신 가짜 =true인수가 표시됩니다.

또한, find찾은 파일 경로를 인쇄하므로 다음과 같은 경우에만 인쇄합니다 ( true뒤에 오는 개행 문자는 명령 대체에 의해 제거되므로 여러 개의 개행 문자도 작동하지만 가끔 파일의 한 줄을 읽을 때, 이런 일은 일어나지 않습니다. 파일에 임의의 파일 이름이 포함될 수 없습니다.$filetruetruefmxfileslistfmxfileslist

find또한 (on, ...)로 시작하는 파일 이름은 차단을 유발한다는 점에 유의하세요 .-!(

-type f일반 파일에 대한 심볼릭 링크 의 경우 false를 반환하는 반면, [ -f "$file" ]위의 내용은 true를 반환합니다. -xtype f둘 사이의 일관성을 위해 또는 -L심볼릭 링크 대상의 수정 시간을 확인하기 위해(역시 ) 특정 GNU가 필요하므로 date -rGNU find4.9 이상을 가정합니다.

if [ "$(
  printf '%s\0' "$file" | find -L -files0-from - -prune -type f -mmin -5 -printf true)" = true ]
then
  printf '%s\n' "$file is found to be regular after symlink resolution and has been last modified within the last 5 minutes or in the future"
fi

find-files0-from -여기서 NUL로 구분된 파일 경로는 위에서 언급한 질식 문제를 피하기 위한 인수가 아닌 stdin(거기에서 가져오며 4.9 이상이 필요함)으로 전달됩니다 .

    then
    cp -a $file /tmp/basefmxfiles

--다시 말하지만, 분할+글로브는 의미가 없으며 옵션 구분 기호도 누락되었습니다 . 미리 디렉터리가 없으면 /tmp/basefmxfiles복사본으로 생성되므로 이를 방지하려면 대상 디렉터리 끝에 $filea 를 추가하는 것이 좋습니다 (또는 여기서는 이미 GNUisms를 사용하고 있으므로 GNU 옵션을 사용합니다). :/cp-t

cp -a -- "$file" /tmp/basefmxfiles/
cp -at /tmp/basefmxfiles -- "$file"
    ls -lrt | grep /tmp/basefmxfiles

ls -lrt현재 작업 디렉토리(여기에 있어야 함)의 내용을 나열하고 /apps/common/bau/base/이를 출력에 포함하는 유일한 방법은 /tmp/basefmxfiles다음과 같은 경우입니다.

lrwxrwxrwx 1 user group 1 May 17 18:11 somelink -> foo/tmp/basefmxfilesbar

심볼릭 링크가 있으므로 이 명령으로 무엇을 하려는지 명확하지 않습니다.

    else 
    echo "But the file is not modified in last 5 minutes"
    fi
else
echo "$0: File '${file}' not found."

여부를 확인하는 else부분 입니다 .[ -f $file ]$file정기적인파일이므로 오류(stderr로 이동해야 함)는 다음과 같아야 합니다.

printf>&2 '%s\n' "$0: File '$file' not found as a regular file."

여기에서 다음 명령을 사용하여 모든 작업을 수행할 수 있습니다 find(역시 GNU find4.9 이상이라고 가정).

cd /apps/common/bau/base || exit
tr '\n' '\0' < /tmp/fmxfileslist |
  find -L -files0-from -                                    \
    -prune                                                  \
    -type f                                                 \
    -printf '%p regular and last modified on %TFT%TT%Tz\n'  \
    '('                                                     \
       -mmin -5 -printf '%p regular and mtime > -5min\n' -o \
          -printf '%p regular but older\n'                  \
    ')' -o -printf '%p not a regular files\n'

액세스할 수 없는 파일의 경우 findstderr에 오류 메시지를 인쇄합니다.

zsh또는 대신 사용할 수 있습니다 sh.

#! /bin/zsh -
cd /apps/common/bau/base || exit

          files=( ${(f)"$(</tmp/fmxfileslist)"} )
       regulars=( $^files(N-.)                  )
recent_regulars=( $^regulars(N-m-5)             )
 older_regulars=( ${regulars:|recent_regulars}  )
   non_regulars=( ${files:|regulars}            )

     accessible=( $^files(N-^@)                 )
   inaccessible=( ${files:|accessible}          ) 

예를 들어, print이러한 배열의 내용은 열에 대해 경외감을 r느끼 거나 반복됩니다 (zsh에는 인용되지 않은 매개변수 확장을 위한 분할+글로브가 없으므로 인용되지 않은 상태로 둘 수 있습니다).1 Cprint -rC1 -- $arrayfor file ($array) something with $file

심볼릭 링크 확인 전후에 파일의 마지막 수정 시간을 얻으려면 stat내장 기능을 사용할 수 있습니다.

zmodload zsh/stat
stat -F %FT%T%z -H after -- $file &&
  stat -LF %FT%T%z -H before -- $file &&
  print -r "mtime before symlink resolution: $before[mtime]; after: $after[mtime]"

¹ BSD에서는 이 구문을 대신 사용할 수 있습니다 find -f "$file" ....

관련 정보