シェルでファイルサイズ(バイト単位)を取得するポータブルな方法?


121

Linuxではを使用しstat --format="%s" FILEていますが、アクセスできるSolarisにはstatコマンドがありません。次に何を使うべきですか?

私はBashスクリプトを書いていて、システムに新しいソフトウェアを実際にインストールできません。

私はすでに使用を検討しました:

perl -e '@x=stat(shift);print $x[7]' FILE

あるいは:

ls -nl FILE | awk '{print $5}'

しかし、これらはどちらも賢明に見えません-ファイルサイズを取得するためだけにPerlを実行していますか?または、2つのコマンドを実行して同じことをしますか?


1
よくbashスクリプトソフトウェアであり、それをシステムに置くことができれば、ソフトウェアをインストールできます。
ちょうど誰か

4
技術的にはそうです。root権限を持っていないので、新しいパッケージをインストールできません。確かにホームディレクトリにインストールすることは可能です。しかし、移植可能なスクリプトを作成し、 "X"マシンにインストールする必要がある場合は、新しい追加パッケージが扱いにくくなります。

回答:


207

wc -c < filename(ワードカウントの略で-c、バイトカウントを出力します)は、移植可能なPOSIXソリューションです。一部のスペースが付加される可能性があるため(Solarisの場合)、出力形式のみがプラットフォーム間で統一されない場合があります。

入力リダイレクトを省略しないでください。ファイルが引数として渡されると、ファイル名はバイトカウントの後に出力されます。

バイナリファイルでは機能しないのではないかと心配していましたが、LinuxとSolarisの両方で問題なく機能します。で試すことができwc -c < /usr/bin/wcます。さらに、POSIXユーティリティは、特に明記されていない限り、バイナリファイルの処理保証されています


67
またはwc -c < file、ファイル名を表示したくない場合も同様です。
caf

34
しかし、私が間違っていない場合wcは、パイプラインでread()ストリーム全体がバイトをカウントする必要があります。ls/のawkソリューションは、(と同様の)サイズ、取得するためにシステムコールを使用する必要があります(O(サイズが)対)線形時間も
jmtd

1
wcフルハードディスクで最後にそれを実行したときは、非常に遅いことを覚えています。最初のスクリプトが完了する前にスクリプトを書き直すことができるほど遅かったので、ここに来て私がどうやってそれをしたのかを思い出しました。
Camilo Martin、

6
私は使用しませんwc -c。見た目はすっきりしますが、速度やリソースの使用にはls+のawk方が適しています。また、wc一部のシステムでは結果の前に空白があり、比較を行う前に空白を削除する必要がある場合があるため、実際に結果も後処理する必要があることを指摘したいと思います。
Haravikk 2013

3
wc -c素晴らしいですが、ファイルへの読み取りアクセス権がないと機能しません。
Silas

41

自分のプログラム(非常に小さい)を作成して、サイズだけを表示することにしました。詳細はこちら:http : //fwhacking.blogspot.com/2011/03/bfsize-print-file-size-in-bytes-and.html

一般的なLinuxツールを使用して、私の考えで最もクリーンな方法は次の2つです。

$ stat -c %s /usr/bin/stat
50000

$ wc -c < /usr/bin/wc
36912

しかし、パラメーターを入力したり、ファイルサイズを取得するためだけに出力をパイプしたりしたくないので、自分のbfsizeを使用しています。


2
問題の説明の最初の行には、statはオプションではなく、wc -cが1年以上の最上位の回答であるため、この回答の目的が何であるかわかりません。

22
重要なのは、GoogleでこのSOの質問を見つけた私のような人々でstat あり、それらのオプションです。

3
私はwc -c、10 MBのファイルに4090ミリ秒かかるのに対してstat -c %s、「0」ミリ秒かかる組み込みシステムで作業しているので、提示された正確な質問に答えられない場合でも、代替ソリューションを用意すると役立つことに同意します。
Robert Calhoun

3
"stat -c"は移植性がなく、MacOSでもLinuxと同じ引数を受け入れません。「wc -c」は、大きなファイルに対しては非常に遅くなります。
Orwellophile 2013年

2
statも移植できません。stat -c %s /usr/bin/stat stat: illegal option -- c usage: stat [-FlLnqrsx] [-f format] [-t timefmt] [file ...]

27

にもかかわらず、du通常、ディスクの使用状況ではなく、実際のデータサイズを印刷し、GNUのcoreutilsのは、duバイト単位でファイルの「見かけのサイズ」を印刷することができます。

du -b FILE

ただし、BSD、Solaris、macOSなどでは機能しません。


3
MacOS Xの上で、brew install coreutilsgdu -b同じ効果を達成します
ホセ・アルバン

1
wc結果を出す前にファイル全体を読み取る必要があるため、この方法を選択しますdu
CousinCocaine 2017年

2
POSIXはdu -bdu根拠の完全に異なるコンテキストで言及しています。
Palec 2017

これはlstat呼び出しのみを使用するので、そのパフォーマンスはファイルサイズに依存しません。より短いstat -c '%s'が直感的ではなく、フォルダの動作が異なります(内部の各ファイルのサイズを印刷します)。
Palec 2017

FreeBSDduはを使用して接近することができますdu -A -B1が、それでも結果を1024Bブロックの倍数で出力します。バイト数を出力するように管理できませんでした。BLOCKSIZE=1その場合512Bブロックが使用されるため、環境での設定でも役に立ちません。
Palec 2017

13

最後に、lsとbash配列拡張を使用することにしました。

TEMP=( $( ls -ln FILE ) )
SIZE=${TEMP[4]}

それは本当にいいわけではありませんが、少なくとも1つのfork + execveを実行し、二次プログラミング言語(perl / ruby​​ / python / whatever)に依存しません


余談ですが、「-ln」の「l」は必要ありません。'-n'は '-ln'とまったく同じです
13:07にバリー

いいえ、ちがいます。出力を比較するだけです。

1
ls -ln FILE | { read _ _ _ _ size _ && echo "$size"; }パイプラインの2番目のステップでは、ビルトインだけを使用するため、ポータブルニーズはフォークではなく、Linux上のBash 4.2.37は2回フォークします(execveただし、まだ1つだけです)。
Palec 2017

read _ _ _ _ size _ <<<"$(exec ls -ln /usr/bin/wc)" && echo "$size"単一のフォークと単一のexecで動作しますが、ヒア文字列には一時ファイルを使用します。here-stringをPOSX準拠のhere-documentに置き換えることで、移植可能にすることができます。ところでexec、サブシェルのに注意してください。これがない場合、Bashはサブシェル用に1つのフォークを実行し、内部で実行されるコマンド用に別のフォークを実行します。これは、この回答で提供するコードの場合です。あまりにも。
Palec 2017

1
-lの存在下で不必要です-nPOSIX lsマンページの引用:-n:(-lell)オプションをオンにしますが、ファイルの所有者またはグループを書き込むときは、ユーザー名またはグループ名ではなく、ファイルの数値UIDまたはGIDをそれぞれ書き込みます。無効化-C-mおよび-xオプションを。
Palec 2017

8

クロスプラットフォームの最速のソリューション(lsに単一のfork()のみを使用し、実際の文字をカウントしようとせず、不要なawk、perlなどを生成しません)。

MacOS、Linuxでテスト済み-Solarisの場合、若干の変更が必要になる場合があります。

__ln=( $( ls -Lon "$1" ) )
__size=${__ln[3]}
echo "Size is: $__size bytes"

必要に応じて、ls引数を簡略化し、$ {__ ln [3]}でオフセットを調整します。

注:シンボリックリンクをたどります。


1
または、シェルスクリプトに次のように入力します。ls -Lon "$ 1" | awk '{print $ 4}'
Luciano

1
@Lucianoあなたは、bashを使用して多くのUNIXコマンドを非効率的な方法で連結するのではなく、bashでタスクを分岐せずにタスクを実行するという点を完全に逃したと思います。
Orwellophile 2016年

8

BSDにはstat、GNU coreutilsのものとは異なるオプションがありますが、同様の機能があります。

stat -f %z <file name> 

これはmacOS(10.12でテスト済み)、FreeBSDNetBSDOpenBSD動作します。


statただし、Solarisにはまったくユーティリティがありません。
Palec 2017

6

ls -n出力を処理する場合、移植性の低いシェル配列の代わりに、位置引数を使用できます。これは、唯一の配列を形成し、標準シェルの唯一のローカル変数です。関数内の位置引数の上書きをラップして、スクリプトまたは関数の元の引数を保持します。

getsize() { set -- $(ls -dn "$1") && echo $5; }
getsize FILE

これによりln -dn、現在のIFS環境変数の設定に従って出力が分割され、位置引数に割り当てられ、5番目の引数がエコーされます。-d性を保証ディレクトリが適切と扱われる-nとは異なり、ユーザー名やグループ名は、解決する必要がないことを保証します-l。また、空白を含むユーザー名とグループ名は、理論的には予想される行構造を壊す可能性があります。通常、これらは許可されていませんが、この可能性により、プログラマーは立ち止まって考えることになります。


5

findGNU fileutilsから使用する場合:

size=$( find . -maxdepth 1 -type f -name filename -printf '%s' )

残念ながら、の他の実装はfind通常ももサポートしていませ-maxdepth-printf。これは、たとえばSolarisやmacOSの場合ですfind


FYI maxdepthは必要ありません。次のように書き直すことができますsize=$(test -f filename && find filename -printf '%s')
Palec、2014

@Palec:-maxdepthfind、再帰的になるのを防ぐことを目的としています(statOPが置き換える必要があるものではないため)。あなたのfindコマンドが不足している-nametest、コマンドは必要ありません。
追って通知があるまで一時停止。

@DennisWilliamson findは、指定された基準に一致するファイルについて、そのパラメーターを再帰的に検索します。パラメータがディレクトリでない場合、再帰は…とても簡単です。したがって、まずfilename実際に存在する通常のファイルであるかどうかをテストし、次にfind、再帰する場所がないファイルのサイズを出力します。
Palec、2014

1
find . -maxdepth 1 -type f -name filename -printf '%s'ファイルが現在のディレクトリにある場合にのみ機能し、ディレクトリ内の各ファイルを引き続き検査する可能性があります。より良い使用(さらに短い!)find filename -maxdepth 1 -type f -printf '%s'
Palec 2017

3

findコマンドを使用して、いくつかのファイルのセットを取得できます(ここでは一時ファイルが抽出されます)。次にdu、コマンドを使用して、-hスイッチを使用して人間が読める形式で各ファイルのファイルサイズを取得できます。

find $HOME -type f -name "*~" -exec du -h {} \;

出力:

4.0K    /home/turing/Desktop/JavaExmp/TwoButtons.java~
4.0K    /home/turing/Desktop/JavaExmp/MyDrawPanel.java~
4.0K    /home/turing/Desktop/JavaExmp/Instream.java~
4.0K    /home/turing/Desktop/JavaExmp/RandomDemo.java~
4.0K    /home/turing/Desktop/JavaExmp/Buff.java~
4.0K    /home/turing/Desktop/JavaExmp/SimpleGui2.java~

2

最初のPerlの例は私には無理のようには見えません。

このような理由で、シェルスクリプト(bash / shなど)の記述から、Perlで最も簡単なスクリプトを除くすべての記述に移行しました。特定の要件のためにPerlを起動する必要があることに気付き、Perlでスクリプトを作成する方が(言語およびCPAN経由で利用できる幅広いライブラリーの点で)おそらくより強力であることに気付きました)そして私が欲しかったものを達成するためのより効率的な方法。

他のシェルスクリプト言語(たとえば、python / ruby​​)にも同様の機能があることに疑いはありません。これらを目的に合わせて評価することもできます。Perlについては、私が使用していてよく知っている言語なので、ここでは説明します。


まあ、私は自分でたくさんのPerlを書いていますが、ツールが私ではなく私のために選択されることがあります:)

-3

SolarisにPerlがある場合は、それを使用してください。それ以外の場合、statがないか、findがGNU findではないため、lsとawkが次善の策になります。


-3

私が使用したSolarisにはトリックがあります。複数のファイルのサイズを要求すると、名前のない合計サイズだけが返されます。2番目のファイルとして/ dev / nullのような空のファイルを含めます。

例:コマンドfileyouwant / dev / null

これがls / wc / etcで機能するサイズコマンドを確認することはできません。残念ながら、それをテストするソラリスボックスがありません。


-4

Linux du -h $FILEではを使用できますが、solarisでも動作しますか?


1
実際には単位を変換できますが、これはファイルデータサイズ(「見かけのサイズ」)ではなくディスク使用量を示しています。
Palec 2017

-7

du -ksを試しましたか| awk '{print $ 1 * 1024}'。それはうまくいくかもしれません。


1
これは、ファイルデータサイズ(「見かけのサイズ」)ではなくディスク使用量を示します。
Palec 2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.