web-dev-qa-db-ja.com

bashスクリプトでファイルのサイズを取得するにはどうすればよいですか?

Bashスクリプトでファイルのサイズを取得するにはどうすればよいですか?

これをbash変数に割り当てて、後で使用できるようにするにはどうすればよいですか?

271
haunted85

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 を参照してください。

262
b01
file_size_kb=`du -k "$filename" | cut -f1`

statを使用する際の問題は、これがGNU(Linux)拡張機能であることです。 du -k および cut -f1 はPOSIXによって指定されているため、どのUnixシステムにも移植できます。

たとえば、Solarisにはbashが同梱されていますが、statは同梱されていません。したがって、これは完全に仮説ではありません。

lsにも同様の問題があり、出力の正確な形式が指定されていないため、その出力の解析を移植性よく行うことはできません。 du -hもGNU拡張機能です。

可能な限りポータブルな構造に固執すれば、将来誰かの生活が楽になります。多分あなた自身のものです。

97
Nemo

"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")"
79
Eugéne

BSD(macOS)のstatには、異なるフォーマット引数フラグと異なるフィールド指定子があります。 man stat(1)から:

  • -f format:指定した形式で情報を表示します。有効なフォーマットの説明については、「フォーマット」セクションを参照してください。
  • ... FORMATSセクション...
  • z:ファイルのサイズ(バイト単位)。

だから今一緒に:

stat -f%z myfile1.txt

注:GNU/Linuxシステムでのstatコマンドの使用方法については、 @ b01の回答 を参照してください。 :)

53
chbrown

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_になります。

  • zshstat 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またはzshstatとは逆になっていることに注意してください。

  • 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では、パイプを開いた後でFIONREADioctl()を使用できます(パイプがハングしないように、読み取り+書き込みモードで)。

_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"_(ファイル内のファイルのディスク使用量が含まれるディレクトリは対象外)。
  • GNU _find -- "$file" -printf '%b\n'_
  • _zstat -L +block -- $file_
  • GNU _stat -c %b -- "$file"_
  • BSD _stat -f %b -- "$file"_
  • Perl -le 'print((lstat shift)[12])' -- "$file"
32

このスクリプトは、ファイルサイズを計算する多くの方法を組み合わせています。

(
  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

22

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
9
user150821

ls -l filenameは、ファイルサイズ、権限、所有者など、ファイルに関する多くの情報を提供します。

5列目のファイルサイズ。バイト単位で表示されます。以下の例では、ファイルサイズは2KB未満です。

-rw-r--r-- 1 user owner 1985 2011-07-12 16:48 index.php

編集:statコマンドほど信頼性が低いようです。

8
Druckles

du filenameは、ディスク使用量をバイト単位で示します。

du -h filename、人間が読める形式でサイズを提供します。

5
Teddy

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はあります。

3
findrbot_admin

委任できるシェルスクリプトで小さなユーティリティ関数を作成します。

#! /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の回答の情報に基づいています。

3
oligofren

もう1つのPOSIX準拠の方法は、awklength()関数と共に使用して、改行文字を除く、入力ファイルの各行の文字数で長さを返すことです。それで

_awk '{ sum+=length } END { print sum+NR }' file
_

NRsumに追加されることを確認します。これにより、ファイルで検出された文字の総数と改行の総数が得られます。 awklength()関数は、デフォルトでは現在の行全体に対するlength($0)を意味する引数を取ります。

0
Inian