Linux に拡張子は必要か?

色々議論はあるようですが、結論から言いましょう。必要です。

では何故、必要かと言う結論に至ったのかを説明していきます。


UNIX / Linux で起こっているファイルの読み出し

そもそもファイルを実行する時に何が起こっているのか?

UNIX / Linux では、ファイル属性として「実行可能フラグ」と呼ばれるものが存在します。

この対象ファイルを実行しようとした時、プログラムローダーと呼ばれるプログラムが先頭の数バイト~数キロバイトのを読み込み、対象が何のファイルかを判定します。

このヘッダーのフォーマットは「/usr/share/misc/magic」とそれをコンパイルした「/usr/share/misc/magic.mgc」によって、「file」コマンドや「magic」関連ライブラリによって判定出来ます。


実行可能なテキストファイルの読み出し

実行可能なテキストファイルの場合、まず先頭の行を読み込みます。そこで、先頭行に指定されたコマンドを実行し、標準入力からファイルの内容が読み込まれます。例外的にコマンドが指定された場合に限り、デフォルトのシェルとして実行され、標準入力からファイルの内容が読み込まれます。ただし先頭の「#!」はスクリプトのコメント行として無視されるため、スクリプトの実行では問題は発生しません。

したがって、実行可能なテキストファイルを実行する場合、拡張子は完全に無視されます。

  • 「test1.sh」 bash スクリプト
    • ファイル内容
      #!/bin/bash
      echo "target Shell Is ${SHELL}";
    • 実行結果
      target Shell Is /bin/bash
    • 説明
      「bash」として実行された。
  • 「test2.sh」 bash スクリプト
    • ファイル内容
      #!/bin/sh
      echo "target Shell Is ${SHELL}";
    • 実行結果
      target Shell Is /bin/bash
    • 説明
      「sh」は「bash」の互換モードなので、「bash」として実行された。
  • 「test3.py」 python3 スクリプト
    • ファイル内容
      #!/bin/python3
      import sysprint( sys.version_info )

    • 実行結果
      sys.version_info(major=3, minor=10, micro=2, releaselevel=’final’, serial=0)

    • 説明
      「python3」として実行された。

    • 実行結果
      sys.version_info(major=3, minor=10, micro=2, releaselevel=’final’, serial=0)
    • 説明
      「python3」として実行された。
  • 「test4.py」 python スクリプト
    • ファイル内容
      #!/bin/python
      pimport sysprint( sys.version_info )
    • 実行結果
      sys.version_info(major=3, minor=10, micro=2, releaselevel=’final’, serial=0)
    • 説明
      「python」は「python3」がデフォルトなので、「python3」として実行された。
  • 「test5.py」 python スクリプト
    • ファイル内容
      #!/bin/env python
      import sysprint( sys.version_info )
    • 実行結果
      sys.version_info(major=3, minor=10, micro=2, releaselevel=’final’, serial=0)
    • 説明
      「env python」は環境変数が有効な状態での「python」なので、デフォルトの「python3」が実行された。
  • 「test6.cat」 cat スクリプト
    • ファイル内容
      #!/bin/cat
      これは文書です。
    • 実行結果
      #!/bin/cat
      これは文書です。

    • 説明
      スクリプトとして「cat」実行され、「cat」が標準入力からファイルの中身を読み込み表示した。
  • 「test7.gawk」gawk スクリプト
    • ファイル内容
      #!/bin/gawk -f
      BEGIN { printf( "This is %s\n", ARGV [ 0 ] ); exit( 0 ); }
    • 実行結果
      This is gawk
    • 説明
      スクリプトとして「gawk」が実行され、プログラム名が表示された。
  • 「deault.sh」 デフォルトシェルスクリプト
    • ファイル内容
      echo "target Shell Is ${SHELL}";
    • 実行結果
      target Shell Is /bin/bash
    • 説明
      ヘッダーが無いのでデフォルトのシェルとして「bash」が実行された。
      ちなみに「file ./deault.sh」とすると「./default.sh: ASCII text」と表示される。

通常のテキストファイルを読み込み

通常、テキストファイルを読み込む場合は拡張子が優先されます。

ではここで、拡張子が無くファイルフォーマットから内容が判断できない場合を考えて見ましょう。

プログラムソースの場合

例えばC言語やそこから派生したC++やJavaなどでは、区別がつかない場合があります。これはスクリプト言語などでも原点と派生物では判断が出来無い場合が多くあります。

従って拡張子が必須となります。

XMLファイルの場合

XMLファイルには、XMLで記述されたXHTMLや各種設定ファイルが存在します。しかしながらそれらは、XMLで表現されたHTMLや設定ファイルであるため、プログラムから判別することは困難です。

例えば「/usr/share/krita」の下には以下のようなXMLファイルが存在します。

$ find /usr/share/krita/ -iname ‘.‘ -exec bash -c ‘( file –mime “{}” | grep -i /xml )’ \;
/usr/share/krita/pykrita/colorspace/Manual.html: text/xml; charset=utf-8
/usr/share/krita/pykrita/documenttools/Manual.html: text/xml; charset=utf-8
/usr/share/krita/pykrita/exportlayers/Manual.html: text/xml; charset=utf-8
/usr/share/krita/pykrita/filtermanager/Manual.html: text/xml; charset=us-ascii
/usr/share/krita/pykrita/lastdocumentsdocker/Manual.html: text/xml; charset=utf-8
/usr/share/krita/pykrita/quick_settings_docker/Manual.html: text/xml; charset=utf-8
/usr/share/krita/pykrita/scripter/Manual.html: text/xml; charset=utf-8
/usr/share/krita/pykrita/tenbrushes/Manual.html: text/xml; charset=utf-8
/usr/share/krita/pykrita/tenscripts/Manual.html: text/xml; charset=utf-8
/usr/share/krita/pykrita/assignprofiledialog/Manual.html: text/xml; charset=utf-8
/usr/share/krita/pykrita/channels2layers/Manual.html: text/xml; charset=us-ascii
/usr/share/krita/pykrita/krita_script_starter/Manual.html: text/xml; charset=us-ascii
/usr/share/krita/pykrita/krita_script_starter/bbdkss.ui: text/xml; charset=us-ascii
/usr/share/krita/pykrita/mixer_slider_docker/Manual.html: text/xml; charset=us-ascii
/usr/share/krita/actions/InteractionTool.action: text/xml; charset=utf-8
/usr/share/krita/actions/KarbonCalligraphyTool.action: text/xml; charset=us-ascii
/usr/share/krita/actions/KisAssistantTool.action: text/xml; charset=us-ascii
/usr/share/krita/actions/KisToolCrop.action: text/xml; charset=us-ascii
/usr/share/krita/actions/KisToolPath.action: text/xml; charset=us-ascii
/usr/share/krita/actions/KisToolPencil.action: text/xml; charset=us-ascii
/usr/share/krita/actions/KisToolPolygon.action: text/xml; charset=us-ascii
/usr/share/krita/actions/KisToolPolyline.action: text/xml; charset=us-ascii
/usr/share/krita/actions/KisToolSelectContiguous.action: text/xml; charset=us-ascii
/usr/share/krita/actions/KisToolSelectElliptical.action: text/xml; charset=us-ascii
/usr/share/krita/actions/KisToolSelectMagnetic.action: text/xml; charset=us-ascii
/usr/share/krita/actions/KisToolSelectOutline.action: text/xml; charset=us-ascii
/usr/share/krita/actions/KisToolSelectPath.action: text/xml; charset=us-ascii
/usr/share/krita/actions/KisToolSelectPolygonal.action: text/xml; charset=us-ascii
/usr/share/krita/actions/KisToolSelectRectangular.action: text/xml; charset=us-ascii
/usr/share/krita/actions/KisToolSelectSimilar.action: text/xml; charset=us-ascii
/usr/share/krita/actions/KisToolTransform.action: text/xml; charset=us-ascii
/usr/share/krita/actions/MoveTool.action: text/xml; charset=us-ascii
/usr/share/krita/actions/PathTool.action: text/xml; charset=us-ascii
/usr/share/krita/actions/SvgTextTool.action: text/xml; charset=us-ascii
/usr/share/krita/actions/krita.action: text/xml; charset=us-ascii
/usr/share/krita/actions/kritamenu.action: text/xml; charset=utf-8
/usr/share/krita/actions/plugin_importer.action: text/xml; charset=us-ascii
/usr/share/krita/actions/tenbrushes.action: text/xml; charset=us-ascii
/usr/share/krita/actions/tenscripts.action: text/xml; charset=us-ascii
/usr/share/krita/actions/threshold.action: text/xml; charset=us-ascii
/usr/share/kritaplugins/metadataeditor/dublincore.xmlgui: text/xml; charset=us-ascii
/usr/share/kritaplugins/metadataeditor/exif.xmlgui: text/xml; charset=us-ascii

ここで、拡張子が「html」、MIMEが「text/xml」となっているのは「xhtml」です。

また、拡張子が「ui」のものはユーザーインターフェース、「action」のものはキーボードショートカットの設定です。

このように、拡張子が無いと何のファイルかを判別できません。


実行可能なバイナリーファイルの読み出し

実行可能なバイナリーファイルでは、例外なくヘッダーが存在します。従って拡張子が無くとも問題はありません。

64ビットバイナリの場合

$ file /usr/bin/ls
/usr/bin/ls: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=8bcdbe642249035a0e971e7ed5cf5f922f94d730, for GNU/Linux 3.2.0, stripped

x86 の命令を持つ64ビットのリトルエンディアン

32ビットWindowsアプリの場合

$ file LineInst.exe
LineInst.exe: PE32 executable (GUI) Intel 80386, for MS Windows

32ビットの80386命令のWindowsアプリ(Wineを使用する事でWindowsアプリを直接実行出来る)

32ビットの DOS/V プログラム

$ file F1026826.exe
F1026826.exe: PE32 executable (console) Intel 80386, for MS Windows

32ビットの80386命令のプログラム(Wineを使用する事で DOS/V プログラムを直接実行出来る)


通常のバイナリーファイルの読み出し

バイナリーファイルは通常、ヘッダーを有しているが必ずではなく、また「zip」と「cbz」は両方とも ZIP ファイルであるため拡張子無しでは判断出来無い。

ZIP ファイルとコミックアーカイブ

$ file files.zip comic.cbz
files.zip: Zip archive data, at least v2.0 to extract, compression method=deflate
comic.cbz: Zip archive data, at least v2.0 to extract, compression method=deflate

ヘッダーが無いデータファイル

$ file XXXX7502.BIN
XXXX7502.BIN: data

結論

以上の理由から、UNIX/Linux に於いても拡張子は必要です。

Facebooktwitterfoursquare

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です