Bashスクリプトでファイルのサイズを取得するにはどうすればよいですか?
これをbash変数に割り当てて、後で使用できるようにするにはどうすればよいですか?
GNUシステムの場合:
stat --printf="%s" file.any
man stat から:
%s合計サイズ(バイト単位)
Bashスクリプトで:
#!/bin/bash
FILENAME=/home/heiko/dummy/packages.txt
FILESIZE=$(stat -c%s "$FILENAME")
echo "Size of $FILENAME = $FILESIZE bytes."
注:Mac OS Xのターミナルでstatを使用する方法については @ chbrown's answer を参照してください。
file_size_kb=`du -k "$filename" | cut -f1`
stat
を使用する際の問題は、これがGNU(Linux)拡張機能であることです。 du -k
および cut -f1
はPOSIXによって指定されているため、どのUnixシステムにも移植できます。
たとえば、Solarisにはbashが同梱されていますが、stat
は同梱されていません。したがって、これは完全に仮説ではありません。
ls
にも同様の問題があり、出力の正確な形式が指定されていないため、その出力の解析を移植性よく行うことはできません。 du -h
もGNU拡張機能です。
可能な限りポータブルな構造に固執すれば、将来誰かの生活が楽になります。多分あなた自身のものです。
"Word count"コマンド(wc
)を使用することもできます:
wc -c "$filename" | awk '{print $1}'
wc
の問題は、ファイル名が追加され、出力がインデントされることです。例えば:
$ wc -c somefile.txt
1160 somefile.txt
ファイルサイズのカウントを取得するためだけに完全なインタープリタード言語またはストリームエディターのチェーンを回避したい場合は、wc
がファイル名を表示しないように、ファイルから入力をリダイレクトするだけです。
wc -c < "$filename"
この最後の形式をコマンド置換で使用すると、以下の Gilles で説明するように、求めていた値をシェル変数として簡単に取得できます。
size="$(wc -c <"$filename")"
BSD(macOS)のstat
には、異なるフォーマット引数フラグと異なるフィールド指定子があります。 man stat(1)
から:
-f format
:指定した形式で情報を表示します。有効なフォーマットの説明については、「フォーマット」セクションを参照してください。z
:ファイルのサイズ(バイト単位)。だから今一緒に:
stat -f%z myfile1.txt
注:GNU/Linuxシステムでのstat
コマンドの使用方法については、 @ b01の回答 を参照してください。 :)
sizeの意味に依存します。
_size=$(wc -c < "$file")
_
ファイルから読み取ることができるバイト数を提供します。 IOW、それはファイルのコンテンツのサイズです。ただし、ファイルの内容は読み取られます(ファイルが通常のファイルである場合、または最適化としてのほとんどのwc
実装における通常のファイルへのシンボリックリンクの場合を除く)。それには副作用があるかもしれません。たとえば、名前付きパイプの場合、読み取られたものを再度読み取ることはできません。_/dev/zero
_や_/dev/random
_など、サイズが無限の場合は、しばらく時間がかかります。つまり、ファイルへのread
権限が必要であり、ファイルの最終アクセスタイムスタンプが更新される可能性があります。
これは標準的で移植可能ですが、一部のwc
実装では、その出力に先行ブランクが含まれる場合があることに注意してください。それらを取り除く1つの方法は、以下を使用することです。
_size=$(($(wc -c < "$file")))
_
または、dash
が出力を生成しない場合(ファイルを開くことができない場合など)にyash
またはwc
の空の算術式に関するエラーを回避するには:
_size=$(($(wc -c < "$file") +0))
_
_ksh93
_にはwc
が組み込まれています(有効にした場合、_command /opt/ast/bin/wc
_として呼び出すこともできます)。これにより、そのシェルの通常のファイルで最も効率的になります。
さまざまなシステムにはstat
というコマンドがあり、stat()
またはlstat()
システムコールへのインターフェイスです。
これらは、iノードにある情報を報告します。その情報の1つは_st_size
_属性です。通常のファイルの場合、これはコンテンツのサイズです(エラーがない場合にそこから読み取ることができるデータの量(これは、ほとんどの_wc -c
_実装が最適化で使用するものです))。シンボリックリンクの場合、これはターゲットパスのバイト単位のサイズです。名前付きパイプの場合、システムに応じて、0または現在パイプバッファーにあるバイト数です。ブロックデバイスについても同じですが、システムに応じて、基になるストレージのサイズまたはバイト単位のサイズが0になります。
その情報を取得するためにファイルへの読み取り権限は必要ありません。リンクされているディレクトリへの検索権限のみが必要です。
年代順に、次のものが存在します。
IRIX stat
(90年代):
_stat -qLs -- "$file"
_
_st_size
_の_$file
_属性を返す(lstat()
)または:
_stat -s -- "$file"
_
_$file
_がシンボリックリンクである場合を除いて同じです。この場合、シンボリックリンク解決後のファイルの_st_size
_になります。
zsh
stat
builtin (現在はzstat
としても知られています)_zsh/stat
_モジュール(_zmodload zsh/stat
_でロードされます)( 1997):
_stat -L +size -- $file # st_size of file
stat +size -- $file # after symlink resolution
_
または変数に格納するには:
_stat -L -A size +size -- $file
_
明らかに、それはそのシェルの中で最も効率的です。
GNU stat
(2001); 2005年以降もBusyBox stat
にあります(GNU stat
からコピー):
_stat -c %s -- "$file" # st_size of file
stat -Lc %s -- "$file" # after symlink resolution
_
(_-L
_の意味はIRIXまたはzsh
stat
とは逆になっていることに注意してください。
BSDs stat
(2002):
_stat -f %z -- "$file" # st_size of file
stat -Lf %z -- "$file" # after symlink resolution
_
または、Perl
などのスクリプト言語のstat()
/lstat()
関数を使用できます。
_Perl -le 'print((lstat shift)[7])' -- "$file"
_
AIXには istat
コマンド もあり、stat()
(lstat()
ではないため、シンボリックリンクでは機能しません)情報をすべてダンプします。たとえば、次のように後処理できます。
_LC_ALL=C istat "$file" | awk 'NR == 4 {print $5}'
_
(@JeffSchallerに 詳細を理解するのに役立つ をありがとう)。
tcsh
内:
_@ size = -Z $file:q
_
(シンボリックリンク解決後のサイズ)
GNUがそのstat
コマンドを導入するずっと前に、同じことをGNU find
コマンドをその_-printf
_述語(すでに1991年):
_find -- "$file" -Prune -printf '%s\n' # st_size of file
find -L -- "$file" -Prune -printf '%s\n' # after symlink resolution
_
ただし、_$file
_が_-
_で始まる場合、またはfind
述語(_!
_、_(
_...など)である場合、問題が1つ発生します。
stat()
/lstat()
情報を取得する標準コマンドはls
です。
POSIXly、あなたがすることができます:
_LC_ALL=C ls -dn -- "$file" | awk '{print $5; exit}'
_
シンボリックリンクの解決後、_-L
_を追加します。 5はデバイスファイルでは機能しません。番目 フィールドは、サイズではなくデバイスのメジャー番号です。
ブロックデバイスの場合、stat()
が_st_size
_に対して0を返すシステムには、通常、ブロックデバイスのサイズを報告する他のAPIがあります。たとえば、Linuxには_BLKGETSIZE64
_ ioctl()
があり、ほとんどのLinuxディストリビューションには、それを利用できるblockdev
コマンドが付属しています。
_blockdev --getsize64 -- "$device_file"
_
ただし、そのためにはデバイスファイルへの読み取り権限が必要です。通常、他の方法でサイズを導出することが可能です。たとえば(まだLinuxで):
_lsblk -bdno size -- "$device_file"
_
空のデバイスを除いて動作するはずです。
すべてのseekableファイル(通常のファイル、ほとんどのブロックデバイス、一部のキャラクターデバイスを含む)に対して機能するアプローチは、ファイルを開いて最後までシークすることです:
zsh
の場合(_zsh/system
_モジュールをロードした後):
_{sysseek -w end 0 && size=$((systell(0)))} < $file
_
_ksh93
_の場合:
_< "$file" <#((size=EOF))
_
または
_{ size=$(<#((EOF))); } < "$file"
_
Perl
:
_Perl -le 'seek STDIN, 0, 2 or die "seek: $!"; print tell STDIN' < "$file"
_
名前付きパイプの場合、一部のシステム(少なくともAIX、Solaris、HP/UX)は、パイプバッファー内のデータの量をstat()
の_st_size
_で使用できるようにします。一部の(LinuxやFreeBSDなど)はサポートしていません。
少なくともLinuxでは、パイプを開いた後でFIONREAD
ioctl()
を使用できます(パイプがハングしないように、読み取り+書き込みモードで)。
_fuser -s -- "$fifo_file" &&
Perl -le 'require "sys/ioctl.ph";
ioctl(STDIN, &FIONREAD, $n) or die$!;
print unpack "L", $n' <> "$fifo_file"
_
ただし、パイプのコンテンツは読み取りませんreadが、名前付きパイプをここで開くだけでも副作用が生じる可能性があることに注意してください。最初にfuser
を使用して、一部のプロセスがそれを緩和するためにすでにパイプを開いていることを確認していますが、fuser
がすべてのプロセスを確認できない可能性があるため、これは確実ではありません。
ここまでは、ファイルに関連付けられたprimaryデータのサイズのみを考慮してきました。これには、メタデータのサイズと、そのファイルを格納するために必要なすべてのサポートインフラストラクチャが考慮されていません。
stat()
によって返される別のiノード属性は_st_blocks
_です。これは、ファイルのデータ(およびLinuxのext4ファイルシステムの拡張属性などのメタデータの一部)を格納するために使用される512バイトブロックの数です。これには、iノード自体や、ファイルがリンクされているディレクトリのエントリは含まれません。
サイズとディスク使用量は、圧縮、スパース性(場合によってはメタデータ)、一部のファイルシステムの間接ブロックなどの追加インフラストラクチャが後者に影響を与えるため、必ずしも密接に関連しているわけではありません。
これは通常、du
がディスク使用量を報告するために使用するものです。上記のコマンドのほとんどは、その情報を取得することができます。
POSIXLY_CORRECT=1 ls -sd -- "$file" | awk '{print $1; exit}'
_POSIXLY_CORRECT=1 du -s -- "$file"
_(ファイル内のファイルのディスク使用量が含まれるディレクトリは対象外)。find -- "$file" -printf '%b\n'
_zstat -L +block -- $file
_stat -c %b -- "$file"
_stat -f %b -- "$file"
_Perl -le 'print((lstat shift)[12])' -- "$file"
このスクリプトは、ファイルサイズを計算する多くの方法を組み合わせています。
(
du --apparent-size --block-size=1 "$file" 2>/dev/null ||
gdu --apparent-size --block-size=1 "$file" 2>/dev/null ||
find "$file" -printf "%s" 2>/dev/null ||
gfind "$file" -printf "%s" 2>/dev/null ||
stat --printf="%s" "$file" 2>/dev/null ||
stat -f%z "$file" 2>/dev/null ||
wc -c <"$file" 2>/dev/null
) | awk '{print $1}'
このスクリプトは、Linux、BSD、OSX、Solaris、SunOSなどの多くのUnixシステムで動作します。
ファイルサイズはバイト数を示します。これは見かけのサイズです。これは、ファイルが通常のディスクで使用するバイトで、特別な圧縮、特別なスパース領域、未割り当てブロックなどはありません。
このスクリプトには、より多くのヘルプとオプションを備えた製品版があります。 https://github.com/SixArm/file-size
statは、システムコールが最も少ない状態でこれを行うようです。
$ set debian-live-8.2.0-AMD64-xfce-desktop.iso
$ strace stat --format %s $1 | wc
282 2795 27364
$ strace wc --bytes $1 | wc
307 3063 29091
$ strace du --bytes $1 | wc
437 4376 41955
$ strace find $1 -printf %s | wc
604 6061 64793
ls -l filename
は、ファイルサイズ、権限、所有者など、ファイルに関する多くの情報を提供します。
5列目のファイルサイズ。バイト単位で表示されます。以下の例では、ファイルサイズは2KB未満です。
-rw-r--r-- 1 user owner 1985 2011-07-12 16:48 index.php
編集:stat
コマンドほど信頼性が低いようです。
du filename
は、ディスク使用量をバイト単位で示します。
du -h filename
、人間が読める形式でサイズを提供します。
AWK 1ライナーを見つけました。バグがありましたが、修正しました。 TeraBytesの後にPetaBytesも追加しました。
FILE_SIZE=234234 # FILESIZE IN BYTES
FILE_SIZE=$(echo "${FILE_SIZE}" | awk '{ split( "B KB MB GB TB PB" , v ); s=1; while( $1>1024 ){ $1/=1024; s++ } printf "%.2f %s", $1, v[s] }')
statがすべてのシステムにあるわけではないので、ほとんどの場合、AWKソリューションを使用できます。例; Raspberry Piにはstatはありませんが、awkはあります。
委任できるシェルスクリプトで小さなユーティリティ関数を作成します。
例
#! /bin/sh -
# vim: set ft=sh
# size utility that works on GNU and BSD systems
size(){
case $(uname) in
(Darwin | *BSD*)
stat -Lf %z -- "$1";;
(*) stat -c %s -- "$1"
esac
}
for f do
printf '%s\n' "$f : $(gzip < "$f" | wc -c) bytes (versus $(size "$f") bytes)"
done
@StéphaneChazelasの回答の情報に基づいています。
もう1つのPOSIX準拠の方法は、awk
をlength()
関数と共に使用して、改行文字を除く、入力ファイルの各行の文字数で長さを返すことです。それで
_awk '{ sum+=length } END { print sum+NR }' file
_
NR
がsum
に追加されることを確認します。これにより、ファイルで検出された文字の総数と改行の総数が得られます。 awk
のlength()
関数は、デフォルトでは現在の行全体に対するlength($0)
を意味する引数を取ります。