天天看點

識别Mac電腦上檔案的指令行技巧

原文連結:File it away

有時你會因一個檔案而迷惑,這個檔案可能是在你的檔案夾中的一個未知類型的檔案,它可能是你的父母或者客戶給你的。不幸的是,你不知道它到底是一種什麼樣的檔案。在Mac上檔案是不帶有拓展名的,是以可能并沒有足夠的資訊來告訴你“Flongnozzle-2012”到底包含了什麼内容。然而終端(Terminal)可以為你提供一些便利,你可以使用一些内嵌的指令行工具來幫助你鑒别檔案。

識别檔案内容

對于這種情況,file指令恰好是我所需要的。file指令可以檢測一個檔案的内容然後試圖去弄清楚它是什麼。

1 2

% file launchHandler.m

launchHandler.m: ASCII C++ program text

當然,這其實是Objective-C檔案,不過終端已經非常接近了,終端将其鑒别為一個内有代碼的檔案。“等等,MarkD(注:作者),它僅僅看下檔案的拓展名不就行了嗎?”file指令也支援這種情況,不過拓展名并不是必須的:

1 2 3

% cp launchHandler.m splunge

% file splunge

splunge: ASCII C++ program text

沒有檔案拓展名,不過我們依然鑒别出了這個檔案是什麼。将file指令指向一個可能包含可執行代碼的檔案或目錄,它會告訴你其内在的結構:

1 2

% file /bin/ls

/bin/ls: Mach-O 64-bit executable x86_64

你可能會說,如果你有一個體積龐大的二進制檔案(例如,原生的App)怎麼辦,下面是辦法:

1 2 3 4

% file /Applications/Reason/Reason.app/Contents/MacOS/Reason

Reason.app/Contents/MacOS/Reason: Mach-O universal binary 

with

2 architectures

Reason.app/Contents/MacOS/Reason (

for

architecture i386): Mach-O executable i386

Reason.app/Contents/MacOS/Reason (

for

architecture x86_64): Mach-O 64-bit executable x86_64

将file指向一個圖檔檔案來看看圖檔的一些資訊:

1 2

% file Flongnozzle-2012

Flongnozzle-2012: PNG image data, 1932 x 904, 8-bit/color RGB, non-interlaced

哦等等,這裡有一個終端的使用小技巧:将檔案的圖示從Finder中拖入終端視窗,這就相當于将你拖動的這個檔案或檔案夾的完整路徑粘貼進去了。

進一步探索

有時file也不會讓你滿意,或者你可能想要知道關于檔案的更多資訊。一般來說,你總是可以通過QuickLook在Finder中浏覽一下檔案,如果這樣不起作用,那麼你可以使用hexdump指令來看看出檔案的位元組數,也可以傳入參數-c來看看翻譯成ASCII碼之後的資訊。

例如,回到我們之前的那個圖檔檔案:

1 2 3 4 5 6

% hexdump -C Flongnozzle-2012 | head

00000000  89 50 4e 47 0d 0a 1a 0a  00 00 00 0d 49 48 44 52  |.PNG........IHDR|

00000010  00 00 07 8c 00 00 03 88  08 02 00 00 00 a2 e0 9b  |................|

00000020  61 00 00 0c 45 69 43 43  50 49 43 43 20 50 72 6f  |a...EiCCPICC Pro|

00000030  66 69 6c 65 00 00 48 0d  ad 57 77 54 53 c9 17 be  |file..H..WwTS...|

00000040  af 24 81 90 84 12 88 80  94 d0 9b 28 bd 4a ef 82  |.$.........(.J..|

在展示出來的資料區并沒有太多有用資訊,但是你可以看到它是PNG類型的,這已經是比較有用了,有些檔案還含有更多字元串類型的内容,下面是對一個從Reason數位音頻工作室獲得的更新檔檔案使用hexdump指令得到的資訊:

1 2 3 4 5 6 7 8 9 10 11

% hexdump -C CV-Spy--md.cmb

00000000  46 4f 52 4d 00 00 03 d8  50 54 43 48 43 41 54 20  |FORM....PTCHCAT |

00000010  00 00 00 04 52 45 46 53  43 4f 49 4e 00 00 00 06  |....REFSCOIN....|

00000020  bc 01 00 00 00 01 43 41  54 20 00 00 00 fc 44 45  |......CAT ....DE|

00000030  56 4c 46 4f 52 4d 00 00  00 f0 44 45 56 49 44 45  |VLFORM....DEVIDE|

00000040  53 43 00 00 00 47 bc 02  01 00 00 07 00 00 00 10  |SC...G..........|

00000050  00 00 00 12 43 56 20 56  61 6c 75 65 73 20 28 30  |....CV Values (0|

00000060  2d 3e 32 35 36 29 00 00  00 00 00 00 00 00 00 00  |->256)..........|

00000070  00 00 16 44 44 4c 20 44  69 67 69 74 61 6c 20 44  |...DDL Digital D|

00000080  65 6c 61 79 20 4c 69 6e  65 00 00 00 04 00 50 41  |elay Line.....PA|

...

如果你之前用過Reason,術語“CV Values”和“DDL Digital Delay Line”你一定不會陌生。

strings指令可以從檔案中得到像字元串一樣的位元組序列:

1 2 3 4 5 6 7 8 9 10

% strings CV-Spy--md.cmb

FORM

PTCHCAT

REFSCOIN

CAT

DEVLFORM

DEVIDESC

CV Values (0->256)

DDL Digital Delay Line

...

屬性值

屬性清單(Property lists)是Mac和iOS系統上的一種标準類型的檔案,将一些可以預知類型的資料有結構地組織起來就構成了我們的plist檔案。在該系統上,一般你看到的屬性清單檔案都是被壓縮成二進制格式的檔案,這樣在讀取時會更快。使用者的偏好設定就被存儲為plist檔案:

1 2 3 4

% pwd

/Users/markd/Library/Preferences

% file com.apple.iphonesimulator.plist

com.apple.iphonesimulator.plist: Apple binary property list

不幸的是,這個壓縮之後的plist檔案是一種非常難讀的檔案:

1 2 3 4 5 6 7 8 9 10

% hexdump -C com.apple.iphonesimulator.plist

00000000  62 70 6c 69 73 74 30 30  dc 01 02 03 04 05 06 07  |bplist00........|

00000010  08 09 0a 0b 0c 0d 0e 0f  10 11 12 13 14 15 16 17  |................|

00000020  18 5e 53 69 6d 75 6c 61  74 65 44 65 76 69 63 65  |.^SimulateDevice|

00000030  5f 10 2f 4e 53 57 69 6e  64 6f 77 20 46 72 61 6d  |_./NSWindow Fram|

00000040  65 20 69 50 68 6f 6e 65  53 69 6d 75 6c 61 74 6f  |e iPhoneSimulato|

00000050  72 57 69 6e 64 6f 77 2e  32 2e 30 2e 37 35 30 30  |rWindow.2.0.7500|

00000060  30 30 5f 10 2f 4e 53 57  69 6e 64 6f 77 20 46 72  |00_./NSWindow Fr|

00000070  61 6d 65 20 69 50 68 6f  6e 65 53 69 6d 75 6c 61  |ame iPhoneSimula|

...

幸運的是,有一個工具plutil指令能将這樣二進制形式的資料轉換為更接近與人類可讀語言的形式:

識别Mac電腦上檔案的指令行技巧

(“!$”快捷鍵用來擷取上一條指令中得最後一個參數)

Spotlight

在解讀一個特定檔案方面,OS可能做得比你想象得更好。Spotlight的工作就是為磁盤上的檔案編制索引,通過查詢中繼資料來讓本地搜尋更友善快捷。你可以通過mdls指令來擷取這個中繼資料,是以你能夠問問Spotlight對于這個檔案都知道些什麼:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

% mdls launchHandler.m

kMDItemContentCreationDate     = 2014-07-02 19:22:02 +0000

kMDItemContentModificationDate = 2014-07-02 19:23:58 +0000

kMDItemContentType             = 

"public.objective-c-source"

kMDItemContentTypeTree         = (

"public.objective-c-source"

,

"public.source-code"

,

"public.plain-text"

,

"public.text"

,

"public.data"

,

"public.item"

,

"public.content"

)

...

kMDItemKind                    = 

"Objective-C Source"

kMDItemLastUsedDate            = 2014-07-02 19:32:46 +0000

kMDItemLogicalSize             = 1443

kMDItemPhysicalSize            = 4096

kMDItemUseCount                = 2

kMDItemUsedDates               = (

"2014-07-02 10:00:00 +0000"

這裡mdls告訴你這個檔案是Objective-C代碼的源檔案,同時還有其他相同類型的辨別符來描述資料,這确實是代碼的源檔案,并且是文本編輯格式。當然也有一些有趣的資料,例如這個檔案到底在磁盤上占據着多少空間,以及這個檔案由多少位元組組成。

加載服務(Launch Services)

另一個維護系統資料庫資訊的工具是加載服務,它決定着哪個應用會打開哪個檔案。輕按兩下一個檔案來打開它?Finder會去詢問加載服務。在指令行使用open指令來打開檔案?系統也會去詢問加載服務,由它來辨識到底由誰去打開檔案。

lsappinfo指令就是一個使用加載服務(當然還有核心應用服務,Core Application Services)的工具,它能給你一些關于現在正在運作的應用的資訊。這與辨識檔案到底是什麼無關,但是有了它,你就能了解到一些很cool的資訊。試一下使用lsappinfo sharedmemory指令來獲得共享記憶體的資訊。或者使用lsappinfo visibleProcessList指令列出一組現可見的應用程式(順序為按視窗從前到後)。

要擷取加載服務的其他特性可以通過API,或者是lsregister。其中lsregister算是一個衆所周知但卻非官方的工具了。lsregister在LaunchServices架構下的Support目錄内,而LaunchServices架構又被包含在CoreServices架構中。在你的機器上,很可能是下面這樣的路徑:

1

/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister

lsregister主要被用于在OS系統上注冊一個檔案,這個檔案将會由特定的應用程式來處理。不過你可以dump它的資料庫來檢視相關資訊,使用:

1

% lsregister -dump > services-db.txt

(要運作該指令,你需要擴充你的PATH,加入Support目錄)。

這條指令産生了大概61000行輸出,是以這對于一個日常教程來說就有些太笨重了,不過浏覽一下也是挺有趣的。

還有一些有用的功能來自于一個調用:LSCopyApplicationURLsForURL。給這個調用傳入一個檔案的路徑作為參數,它會傳回一組可以處理該檔案的應用集合。它有不同的查詢模式,像“能打開這個檔案的所有的應用程式有哪些?”,或者“能編輯這個檔案的所有應用程式有哪些?”加載服務并不像file指令一樣去内探這個檔案的結構。取而代之的是,它利用檔案的拓展名、源代碼、模糊比對來找出合适的應用。

這裡有一個小工具,它需要在指令行傳入一個檔案名。通過調用LSCopyApplicationURLsForURL,列印出比對出來的應用程式的數組。你可以在這裡找到這個源代碼。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47

@import Foundation;

@import CoreServices;

// clang -g -fobjc-arc -fmodules launchHandler.m -o launchHandler

int main (int argc, const char *argv[]) {

// Rudimentary argument checking.

if

(argc != 2) {

printf (

"usage: %s filename\n"

, argv[0]);

return

-1;

}

const char *filename = argv[1];

// Get a string of the full path of the file, using realpath() as the workhorse

char pathbuffer[MAXPATHLEN];

char *fullpath = realpath (filename, pathbuffer);

if

(fullpath == NULL) {

fprintf (stderr, 

"could not find %s\n"

, filename);

return

-1;

}

NSURL *url = [NSURL fileURLWithPath: @( fullpath )];

// Ask launch services for the different apps that it thinks could edit this file.

// This is usually a more useful list than what can view the file.

LSRolesMask roles = kLSRolesEditor;

CFArrayRef urls = LSCopyApplicationURLsForURL((__bridge CFURLRef)url, roles);

NSArray *appUrls = CFBridgingRelease(urls);

// Extract the app names and sort them for prettiness.

NSMutableArray *appNames = [NSMutableArray arrayWithCapacity: appUrls.count];

for

(NSURL *url 

in

appUrls) {

[appNames addObject: url.lastPathComponent];

}

[appNames sortUsingSelector: @selector(compare:)];

// Finally emit to the user.

for

(NSString *appName 

in

appNames) {

printf (

"%s\n"

, appName.UTF8String);

}

return

0;

// main

最有趣的部分是這裡用的是realpath()庫,通過調用它來将指令行參數中的檔案名轉換為完整路徑(是以你不用擔心如果使用者到底傳入的是一個相對路徑,還是一個絕對路徑,還是一個帶~的路徑),然後将它傳入LSCopyApplicationURLsForURL,這裡還使用了kLSRolesEditor,因為它可以傳回最合理的一組應用程式。有時候選的應用程式也能給你一些線索來判斷這個檔案到底是什麼。

1 2 3 4 5 6 7 8 9 10 11 12 13 14

% ./launchHandler launchHandler.m

TextEdit.app

Xcode-4.6.app

Xcode-5.0.2.app

Xcode.app

Xcode6-Beta2.app

% ./launchHandler someGraphic.png

Acorn.app

ColorSync Utility.app

Preview.app

% ./launchHandler ./Flongnozzle-2012

%

不幸的是,它并不能解決“Flongnozzle”是什麼的問題,因為這個檔案沒有拓展名或者其他有用的檔案類型的資訊。

其他工具

可用的指令行工具集非同尋常得多,是以我很可能落下了一個或者兩個或者更多其他的工具來幫助你辨識一個未知檔案。如果你有一個非常喜歡的小技巧,請留下一條評論!

翻譯:Mr_cyz,于1-19日首發于CocoaChina

繼續閱讀