我正在編寫一個 shell 腳本,它使用 來shasum
檢查目錄的內容是否已更改。
在 Linux 和 FreeBSD 上,shasum
當我這樣做時,它們有相同的行為,shasum <directory>
但是,在 MacOS 上,shasum
給我一個哈希值僅適用於文件。
自由BSD
$ shasum CONTENTS/
7f986e5e5289c59db1bba48df92ffe4707830aaa CONTENTS/
Linux
$ shasum CONTENTS/
7f986e5e5289c59db1bba48df92ffe4707830aaa CONTENTS/
蘋果系統
$ shasum CONTENTS/
shasum: CONTENTS/:
如何計算 MacOS 中目錄的雜湊值?
嘗試 1:將 TAR 與管道一起使用
嘗試使用,但似乎這個 tar 選項在 MacOS 上不起作用。
tar cO CONTENTS/ | shasum
tar: Option -O is not permitted in mode -c
da39a3ee5e6b4b0d3255bfef95601890afd80709 -
試試 2:使用 FIND/EXEC
MacOS 和 FreeBSD 之間是一致的,但 Linux 回傳了一個奇怪的哈希值
find CONTENTS -type f -exec shasum {} \; | sort -k 2 | shasum
Linux
c2ddb9bc5f543e956f5cdcc76750cb78cc5f26f3
自由BSD
3ac2a9d4e2fc5d2d2ec3c7f612e680990cc35824
蘋果系統
3ac2a9d4e2fc5d2d2ec3c7f612e680990cc35824
關於焦油的其他發現
tar
會很棒,因為它「歸檔」一個資料夾,然後我就可以了,但是「行走」資料夾結構shasum
的順序是tar
跨作業系統不一致。正如一些幫助者在評論中提到的,我應該tar
在所有系統中使用相同的版本。
舉個例子,在系統 1 上我有這個指令:
drwxr-xr-x 0 root wheel 0 27 Jul 07:23 usr/
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/aaa
drwxr-xr-x 0 root wheel 0 27 Jul 07:25 usr/f1/
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/f1/aaa
drwxr-xr-x 0 root wheel 0 27 Jul 07:25 usr/f1/f0/
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/f1/f0/aaa
drwxr-xr-x 0 root wheel 0 27 Jul 07:25 usr/f2/
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/f2/aaa
drwxr-xr-x 0 root wheel 0 27 Jul 07:25 usr/f2/f1/
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/f2/f1/aaa
drwxr-xr-x 0 root wheel 0 27 Jul 07:25 usr/f2/f1/f0/
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/f2/f1/f0/aaa
drwxr-xr-x 0 root wheel 0 27 Jul 07:25 usr/f3/
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/f3/aaa
drwxr-xr-x 0 root wheel 0 27 Jul 07:25 usr/f3/f2/
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/f3/f2/aaa
drwxr-xr-x 0 root wheel 0 27 Jul 07:25 usr/f3/f2/f1/
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/f3/f2/f1/aaa
在系統 2 上我有以下指令:
drwxr-xr-x 0 root wheel 0 27 Jul 07:23 usr/
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/aaa
drwxr-xr-x 0 root wheel 0 27 Jul 07:25 usr/f1/
drwxr-xr-x 0 root wheel 0 27 Jul 07:25 usr/f2/
drwxr-xr-x 0 root wheel 0 27 Jul 07:25 usr/f3/
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/f3/aaa
drwxr-xr-x 0 root wheel 0 27 Jul 07:25 usr/f3/f2/
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/f3/f2/aaa
drwxr-xr-x 0 root wheel 0 27 Jul 07:25 usr/f3/f2/f1/
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/f3/f2/f1/aaa
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/f2/aaa
drwxr-xr-x 0 root wheel 0 27 Jul 07:25 usr/f2/f1/
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/f2/f1/aaa
drwxr-xr-x 0 root wheel 0 27 Jul 07:25 usr/f2/f1/f0/
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/f2/f1/f0/aaa
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/f1/aaa
drwxr-xr-x 0 root wheel 0 27 Jul 07:25 usr/f1/f0/
-rw-r--r-- 0 root wheel 0 27 Jul 07:25 usr/f1/f0/aaa
從tar
角度來看,一切都很好,但由於順序不同,會shasum
產生不同的雜湊值。
結論
shasum
在 Linux 和 BSD 中檢查單一檔案雜湊是一致的,但是,當涉及目錄時,一致性僅發生在 MacOS 和 FreeBSD 上,這可能是由於檔案的排序方式所致。
如果使用該命令強制排序find
,則僅在 FreeBSD 和 MacOS 中獲得一致性,但是此方法的時間限制,因為它需要大量時間來計算每個檔案的雜湊值,然後計算整個結構雜湊值。
使用tar
建立臨時檔案然後執行ashasum
也發現Linux和BSD之間不一致,可能是因為歸檔方法的不同。
我認為前進的唯一出路是重新設計我的解決方案。
答案1
mtree
是您想要的工具。
認為:
$ mkdir foo
$ date > foo/date1; sleep 3
$ date > foo/date2; sleep 3
$ date > foo/date3
$ grep . foo/*
foo/date1:Wed Jul 24 16:11:32 PDT 2019
foo/date2:Wed Jul 24 16:11:35 PDT 2019
foo/date3:Wed Jul 24 16:11:38 PDT 2019
$ find . -ls
7318841 0 drwxr-xr-x 3 admin staff 102 Jul 24 16:11 .
7318847 0 drwxr-xr-x 5 admin staff 170 Jul 24 16:11 ./foo
7318849 8 -rw-r--r-- 1 admin staff 29 Jul 24 16:11 ./foo/date1
7318851 8 -rw-r--r-- 1 admin staff 29 Jul 24 16:11 ./foo/date2
7318853 8 -rw-r--r-- 1 admin staff 29 Jul 24 16:11 ./foo/date3
建立目錄的參考清單foo
並將其儲存在foo.mtree
:
$ mtree -c -K sha256digest -p foo > foo.mtree
現在去弄亂該目錄中的任何檔案。
$ touch foo/date3
再次運行mtree
並向其傳遞您之前創建的清單,並mtree
會告訴您發生了什麼變化:
$ mtree -p foo < foo.mtree || echo fail
date3 changed
modification time expected Wed Jul 24 16:11:38 2019 found Wed Jul 24 16:14:00 2019
fail
$ echo '$ date > foo/date2' >> bar
$ mtree -p foo < foo.mtree || echo fail
date2 changed
modification time expected Wed Jul 24 16:11:35 2019 found Wed Jul 24 16:19:40 2019
SHA-256 expected c76a568f08d98c2830f2fdfb42415c3ec15341b8741450d4bbd863f1d5c4c691 found ddcf8d07785bfe4d031a989339835dc3b8b44653019568dcee612c44fc8e2f70
date3 changed
modification time expected Wed Jul 24 16:11:38 2019 found Wed Jul 24 16:14:00 2019
fail
foo
也會報告自清單建立以來遺失或新增的任何文件:
$ mv foo/date1 foo/date4
$ mtree -p foo < foo.mtree || echo fail
. changed
modification time expected Wed Jul 24 16:11:38 2019 found Wed Jul 24 16:21:38 2019
date2 changed
modification time expected Wed Jul 24 16:11:35 2019 found Wed Jul 24 16:19:40 2019
SHA-256 expected c76a568f08d98c2830f2fdfb42415c3ec15341b8741450d4bbd863f1d5c4c691 found ddcf8d07785bfe4d031a989339835dc3b8b44653019568dcee612c44fc8e2f70
date3 changed
modification time expected Wed Jul 24 16:11:38 2019 found Wed Jul 24 16:14:00 2019
date4 extra
./date1 missing
fail
答案2
林特會做你想做的事(我認為是)。
相關重點:
- 預設情況下它不使用 SHA,但可以告訴它。
- 它可以透過自製程式安裝在 MacOS 上。
- 預設情況下,它不會計算單一指定目錄的校驗和。可以告訴它從給定的起點計算所有目錄的校驗和,作為查找該點以下“重複”目錄的一種方式。但作為副作用,也會完全照你的要求去做。
- 對於您正在尋找的內容來說,這可能有點過分了,您可能需要一段時間才能找出要使用的最佳選項標誌,但它非常強大。
- 弄清楚要使用哪些標誌可能很棘手。取得目錄校驗和很容易,但是取得它不是做其他事情,可能會很棘手。 (儘管要明確,它實際上並沒有修改任何內容。最多,它會產生一個 shell 腳本,您可以稍後手動運行該腳本,以便根據需要進行修改。您似乎需要的是 JSON 和/或 CSV 輸出文件,這將為您提供您正在尋找的目錄校驗和。
我在 bash 腳本中使用 rmlint 來尋找重複的目錄。這是一個命令,它將最少地執行您想要的操作,並且盡可能少地執行其他操作:
rmlint "base/dir/to/start/from" --see-symlinks --hidden --algorithm=sha256 --types=none,duplicatedirs --no-backup -o csv:log.csv