두 파일의 수정 날짜 비교

두 파일의 수정 날짜 비교

저는 보편적인 편집/번역 시스템을 만들고 있습니다. 파일이 컴파일/변환되었는지 확인하는 한 가지 방법은 소스 파일과 대상 파일의 수정 날짜를 비교하는 것입니다.

이 작업을 수행하려면 bash 스크립트를 작성해야 합니다.

source_file=foo;
target_file=bar;

stat_source=$(stat source_file);
stat_target=$(stat target_file);

그런데 통계 출력에서 ​​날짜를 추출하고 비교하려면 어떻게 해야 합니까? stat파일이 마지막으로 수정된 시기를 비교하는 것보다 더 좋은 방법이 있습니까 ?

로그 파일에서 stat를 호출하면 다음과 같은 결과가 나타납니다.

16777220 12391188 -rw-r--r-- 1 alexamil staff 0 321 "Jun 22 17:45:53 2017" "Jun 22 17:20:51 2017" "Jun 22 17:20:51 2017" "Jun 22 15:40:19 2017" 4096 8 0 test.log

AFAICT, 시간 단위는 초 이상입니다. 가능하다면 이보다 더 세분화된 것을 얻어야 합니다.

답변1

사용하고 있다는 점을 고려하면stattest(비슷한 기능이지만 BSD와 GNU의 출력 형식은 다릅니다.) 직접 비교를 수행하는 이 유틸리티를 사용할 수도 있습니다 .

   FILE1 -nt FILE2
          FILE1 is newer (modification date) than FILE2

   FILE1 -ot FILE2
          FILE1 is older than FILE2

귀하의 예에서는

if [ "$source_file" -nt "$target_file" ]
then
    printf '%s\n' "$source_file is newer than $target_file"
fi

이 기능은 POSIX에서는 사용할 수 없습니다(해당 내용 참조).선적 서류 비치test), 그 이유는 다음과 같습니다.

새로 발명되었거나 KornShell에서 나온 일부 추가 기본 명령은 조건부 명령([[]])의 일부로 초기 제안에 나타났습니다. s1 >s2, s1 <s2, str = 패턴, str != 패턴, f1-ntf2, f1-otf2 및 f1 -ef f2. 조건부 명령이 셸에서 제거되면 sh 유틸리티의 기록 구현에 내장된 테스트 유틸리티에 아직 포함되지 않았기 때문에 테스트 유틸리티로 전송되지 않습니다.

그러나 이는 향후 변경될 수 있습니다.이 기능이 널리 지원되기 때문입니다.

피연산자가 심볼릭 링크인 경우 심볼릭 링크 대상의 수정 시간이 고려된다는 점에 유의하세요(일반적으로 원하는 것이니 find -newer그렇지 않은 경우 사용하세요). 심볼릭 링크를 확인할 수 없을 때 구현 간 동작(일부는 기존 파일이 항상 확인되지 않은 파일보다 최신이라고 생각하고 일부는 항상 보고함)잘못된구문 분석할 수 없는 피연산자가 있는 경우).

또한 모든 구현이 1초 미만의 세분성을 지원하는 것은 아닙니다(예: 버전 4.4 기준으로 bash's test/ 내장 기능은 여전히 ​​지원하지 않지만 GNU 및/또는 ' 내장 기능은 적어도 GNU/Linux에서는 지원합니다).[testtestzshksh93

참고로:

  • GNU test유틸리티 구현의 경우(비록 Bourne과 같은 쉘에는 일반적으로 이를 숨기는 / 내장 명령이 fish있으므로 우회 하기보다는 사용하십시오),test[env testtest시간을 가져라test.c에서 읽고 struct timespec,
  • 옵션-nt이 데이터를 사용

답변2

이 Linux 시스템에서 테스트되었습니다. 파일 시간을 테스트하는 일반적인 방법은 셸을 사용하는 것입니다.

[ file1 -nt file2 ] && echo "yes"

몇 초 안에 완료될 수 있을 것 같습니다. 이렇게 하면 1초 미만의 시간 차이가 있는 파일에 영향을 미치며 차이가 감지되지 않습니다.

$ touch file2; sleep 0.1; touch file1; [ file1 -nt file2 ] && echo "yes"

문제를 확인하려면(점 뒤의 시간은 나노초 단위임):

$ ls --time-style=full-iso -l file?
-rw-r--r-- 1 user user 0 2017-06-23 01:37:01.707387495 -0400 file1
-rw-r--r-- 1 user user 0 2017-06-23 01:37:01.599392538 -0400 file2

file1보다 약간 최신입니다 file2.

이제 문제는 시간 값을 올바르게 처리하는 방법입니다.

한 가지 해결책은 ls의 형식화된 출력을 사용하는 것입니다.

$ ls --time-style=+%s.%N -l file?
-rw-r--r-- 1 user user 0 1498196221.707387495 file1
-rw-r--r-- 1 user user 0 1498196221.599392538 file2

시간을 두 개의 변수로 추출합니다(점 없이).

$ file1time=$(ls --time-style=+%s%N -l file1 | awk "{print(\$6)}")
$ file2time=$(ls --time-style=+%s%N -l file2 | awk "{print(\$6)}")

그리고 시간을 비교하십시오(나노초 단위의 시간은 64비트 값에 거의 맞지 않습니다. 시스템이 64비트를 사용하지 않으면 이 비교는 실패합니다).

$ [ $file1time -gt $file2time ] && echo "yes"
yes

이는 file1더 많다는 것을 보여준다.file2


ls원하는 형식을 얻을 수 없다면 stat를 시도해 볼 수 있습니다 .

$ stat file1
  File: file1
  Size: 0               Blocks: 0          IO Block: 4096   regular file
Device: 805h/2053d      Inode: 9180838     Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1000/    user)   Gid: ( 1000/    user)
Access: 2017-06-23 01:37:01.707387495 -0400
Modify: 2017-06-23 01:37:01.707387495 -0400
Change: 2017-06-23 01:37:01.707387495 -0400
 Birth: -

출력에 나노초가 표시되면 시간을 구문 분석하고 형식을 지정하려면 날짜가 필요합니다.

$ stat --printf='%y\n' file1
2017-06-23 01:37:01.707387495 -0400

$ date +'%s%N' -d "$(stat --printf='%y\n' file1)" 
1498196221707387495

다른 모든 것은 동일합니다. file1과 file2의 결과를 두 변수에 할당하고 수치 비교를 수행합니다.

답변3

내장되지 않은 Linux를 사용하려는 경우 testGNU coreutils의 일부인 외부 명령을 사용할 수 있습니다. ( test대부분의 쉘에 대한 또 다른 이름 [이며 내장되어 있습니다). 나노초 단위(최대 파일 시스템 보고 정확도)를 갖습니다.

/usr/bin/test "$target" -nt "$source"

이 연산자는 POSIX에서 정의되지 않지만 dash, bash, pdksh, mksh, ATT ksh, zsh, GNU coreutils 및 BusyBox를 -nt포함한 많은 구현에 존재합니다 . test그러나 많은 구현(dash, bash, pdksh, mksh, BusyBox - Debian jessie에서 테스트됨)은 1초 단위만 지원합니다.

그러나 작업을 위해 특별히 설계된 도구를 사용하는 것이 더 나은 생각일 것입니다.만들다. 특정 파일이 다른 파일보다 최신일 때만 명령을 실행하는 것이 make의 전부입니다. 이름이 지정된 파일에 다음을 포함합니다 Makefile(각 명령줄 앞에 탭이 필요합니다).

target: source
    echo This command is only executed if target is newer than source
    do_stuff <source >$@

make target이를 생성한 명령을 실행하려면 실행하세요 . target존재하고 보다 최신인 경우 source명령이 실행되지 않습니다. 자세한 내용은 make의 문서 중 일부를 읽어보세요.

답변4

POSIXly에서는 다음을 사용합니다 find.

if find "$source_file" -prune -newer "$target_file" | grep -q '^'; then
  printf '%s\n' "$source_file is newer than $target_file"
else
  echo "It's not newer or one of the files is not accessible"
fi

심볼릭 링크의 경우 심볼릭 링크 자체의 실행 시간을 비교합니다. 심볼릭 링크의 대상을 비교하려면 -H또는 -L옵션을 추가하세요.

이 가정은 술어 중 하나로 $source_file시작하지도 -않고 해당 하지도 않습니다. find임의의 파일 이름을 처리해야 하는 경우 먼저 다음을 수행해야 합니다.

case $source_file in
  (["-+()!"]*) source_file=./$source_file;;
esac

GNU 및 FreeBSD find구현은 최소한 1초 미만의 세분성을 지원합니다. AFAICT, macos는 HFS+ 파일 시스템의 파일 속성에 최소한 1초 미만의 정보를 저장하지 않는 것 같습니다.

관련 정보