効率的なクロスOSファイルサイズシェル機能

効率的なクロスOSファイルサイズシェル機能

オペレーティングシステム全体でファイルサイズを確認するより簡単な方法を探しています。 wc -cを使用できますが、大容量ファイルに与えるパフォーマンスの影響が心配されます。 (文字数だけを計算し、後で統計を実行しないとしますか?)

以下はLinuxとmacos(そしておそらくbsd)で動作します。良いパフォーマンスを持つより簡単な方法はありますか?

function filesize
{
    local file=$1
    size=`stat -c %s $file 2>/dev/null` # linux
    if [ $? -eq 0 ]; then
        echo $size
        return 0
    fi

    eval $(stat -s $file) # macos
    if [ $? -eq 0 ]; then
        echo $st_size
        return 0
    fi

    echo 0
    return -1
}

答え1

wcGNU coreutilsのソースcoreutils/src/wc.c(つまり、組み込まれていないLinuxとCygwinのバージョン)から:

 When counting only bytes, save some line- and word-counting
 overhead.  If FD is a 'regular' Unix file, using lseek is enough
 to get its 'size' in bytes.

したがって、wc -cバイト数を使用するとうまくいきます。

大容量ファイル(読み取りに時間がかかるファイルなど)でこの最適化を簡単にテストできます。 9.9Gbファイルは私のサーバーwc -cでリアルタイムで0.015秒かかりました。その時点でファイル全体を転送できると嬉しいですが、残念ながら私のギガビットイーサネット速度はそうではありません。/dev/nullネットワーク)。

答え2

私は除いてstatPOSIXではないので、perlandよりも欠けている可能性が高いです。lsawk

wcまた、このオプションを使用するとGNU実装が最適化されますが、移植可能なスクリプトを提供するためにこのオプションに依存してはならないため、この可能性も排除しました。さらに、基準を満たさない一部の製品は数量を返すことがあります。wc-cwc -c数値必ずしも数量と同じではありません。バイトロケール設定によって異なります。

以下は、引数として提供されたファイルのサイズを報告する標準ユーティリティのみに基づくソリューションです。

filesize() {
        [ -f "$1" ] && ls -dnL -- "$1" | awk '{print $5;exit}' || { echo 0; return 1; }
}

報告されたサイズは、使用されているファイルシステム、スパースファイルのサポート、圧縮または重複排除などのオプションによって、ディスク上のファイルコンテンツの実際のサイズより大きくても小さくてもかまいません。

答え3

私はこれを使うべきだと思います。私が見つけたばかりによると、これはPOSIXの指定標準ユーティリティ。

du

POSIX 指定オプションは次のとおりです。

duユーティリティはXBDユーティリティの構文ガイドラインに準拠する必要があります。

次のオプションをサポートする必要があります。

  • -a デフォルトの出力に加えて、指定されたファイルをルートとするファイル階層で、ディレクトリ以外の種類の各ファイルサイズを報告します。ファイルオペランドとして提供されている非ディレクトリは、-aオプションがあるかどうかにかかわらず、常にリストする必要があります。
  • -H コマンドラインにシンボリックリンクが指定されている場合、duはリンクが参照するファイルまたはファイル階層のサイズを計算します。
  • -k デフォルトの512バイト単位ではなく1024バイト単位でファイルサイズを書き込みます。
  • -L シンボリックリンクがコマンドラインで指定されている場合、またはファイル階層のナビゲーション中に見つかった場合、duはリンクが参照するファイルまたはファイル階層のサイズを計算する必要があります。
  • -s デフォルト出力ではなく、指定された各ファイルの合計のみが報告されます。
  • -x ファイルサイズを評価すると、fileオペランドで指定されたファイルと同じデバイスを持つファイルのみが評価されます。相互に排他的な複数のオプション-Hと-Lを指定することは、エラーと見なすべきではありません。指定された最後のオプションによってユーティリティの動作が決まります。

しかし、問題は、ファイルサイズを報告せずに代わりに報告することです。ディスク使用量。それらは異なる概念であり、違いはファイルシステムによって異なります。ファイルセットのファイルサイズを取得するには、次のように使用できます。

{   echo
    /usr/bin/ls -ndL .//*
} | sed '/\n/P;//D;N
\|//|s|\n|/&/|
$s|$|/|;s| .//|/\
/|;2!P;D'

これは非常に単純なアイデアです。sedの出力に2行のアドレス指定可能ウィンドウを保持します。lsこれはスライド入力のように機能します。常にパターンスペースで最も古い2行をP印刷して削除し、それを置き換えるために追加の入力行をDドラッグします。Nデフォルトでは、これは1行の予測です。

いくつかの深刻な書き込み欠陥があります。たとえば、私の便宜のために処理を避け、lsリンク自体ではなくリンク先について報告するオプションを使用します。また、現在のディレクトリだけがグローバルディレクトリであると仮定します。時によって異なります。-> linkpath-Lls/ いいえファイル名に表示されます。区切り記号だからです。これは実際にはこの種の作業では非常に一般的です。cdディレクトリに入り、cd -終了します。

これらはすべて数行以上で処理できますが、これは単なるデモです。

ここで重要な部分と将来見通すべき理由は次のとおりです。

\|//|s|\n|/&/|

パターンスペースの最新行に文字列が含まれている場合は、最も古い行の末尾に.//aを追加し、最新行の先頭にaを挿入します。その後、それを別の行とスラッシュを区別する2行を追加しました。//.//\n

だからこれ:

drwxr-xr-x 1 1000 1000        6 Aug  4 14:40 .//dir*
drwxr-xr-x 1 1000 1000        0 Aug  4 14:40 .//dir1
drwxr-xr-x 1 1000 1000        6 Aug  8 17:34 .//dir2
drwxr-xr-x 1 1000 1000       22 Aug 10 18:12 .//dir3
drwxr-xr-x 1 1000 1000       16 Jul 11 21:59 .//new
-rw-r--r-- 1 1000 1000        8 Aug 20 11:32 .//newfile
-rw-r--r-- 1 1000 1000        0 Jul  6 11:24 .//new
file
-rw-r--r-- 1 1000 1000        0 Jul  6 11:24 .//new
file
link

次のようになります。

/drwxr-xr-x 1 1000 1000        6 Aug  4 14:40/
/dir*/
/drwxr-xr-x 1 1000 1000        0 Aug  4 14:40/
/dir1/
/drwxr-xr-x 1 1000 1000        6 Aug  8 17:34/
/dir2/
/drwxr-xr-x 1 1000 1000       22 Aug 10 18:12/
/dir3/
/drwxr-xr-x 1 1000 1000       16 Jul 11 21:59/
/new/
/-rw-r--r-- 1 1000 1000        8 Aug 20 11:32/
/newfile/
/-rw-r--r-- 1 1000 1000        0 Jul  6 11:24/
/new
file/
/-rw-r--r-- 1 1000 1000        0 Jul  6 11:24/
/new
file
link/

しかし、何が役に立ちますか?まあ、これはすべての違いを作ります:

IFS=/; set -f; set $(set +f
{   echo 
/usr/bin/ls -ndL .//*
}| sed '/\n/P;//D;N
\|//|s|\n|/&/|
$s|$|/|;s| .//|/\
/|;2!P;D'
)

unset IFS
while [ -n "$2" ]
do  printf 'Type :\t <%.1s>\tSize :\t %.0s%.0s%.0s<%d>%.0s%.0s%.0s\nFile :\t %s\n' \
        $2 "<$4>"
shift 4; done

出力

Type :   <d>    Size :   <6>
File :   <dir*>
Type :   <d>    Size :   <0>
File :   <dir1>
Type :   <d>    Size :   <6>
File :   <dir2>
Type :   <d>    Size :   <22>
File :   <dir3>
Type :   <d>    Size :   <16>
File :   <new>
Type :   <->    Size :   <8>
File :   <newfile>
Type :   <->    Size :   <0>
File :   <new
file>
Type :   <->    Size :   <0>
File :   <new
file
link>

答え4

おそらく、より簡単で移植性に優れていますperl

filesize() {
  file="$1"
  if [ -e "$file" ]; then
    size="$(perl -e 'print -s shift' "$file")"
    printf '%s\n' "$size"
    return 0
  else
    printf "0\n"
    return -1
  fi
}

関連情報