효율적인 크로스 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

나는 제외 stat하고 POSIX가 아니므로 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의 출력에 두 줄의 주소 지정 가능 창을 유지합니다. ls이는 슬라이딩 입력처럼 작동합니다. 항상 패턴 공간에서 가장 오래된 두 줄을 P인쇄한 다음 삭제하고, 이를 대체하기 위해 추가 입력 줄을 D끌어옵니다 . N기본적으로 이는 한 줄의 예측입니다.

몇 가지 심각한 쓰기 결함이 있습니다. 예를 들어, 내 편의를 위해 처리를 피하고 ls링크 자체가 아닌 링크 대상에 대해 보고하는 옵션을 사용합니다. 또한 현재 디렉터리만 전역 디렉터리라고 가정합니다. 때에 따라 다르지-> linkpath-Lls/ 아니요파일 이름에 표시됩니다. 구분 기호이기 때문입니다. 이것은 실제로 이런 종류의 작업에서 매우 일반적입니다. cd디렉토리에 들어간 다음 cd -종료합니다.

이 모든 것은 몇 줄 또는 그 이상으로 처리할 수 있지만 이는 단지 데모일 뿐입니다.

여기서 핵심 부분과 앞으로 전망해야 할 이유는 다음과 같습니다.

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

패턴 공간의 최신 라인에 문자열이 포함되어 있으면 가장 오래된 라인의 끝에 .//a를 추가 하고 최신 라인의 선두에 a를 삽입합니다. 그런 다음 이를 또 다른 줄줄이와 슬래시를 구분하는 줄 두 개를 더 추가했습니다.//.//\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
}

관련 정보