쉘에서 파일 크기 (바이트)를 가져 오는 이식 가능한 방법?


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
기술적으로-사실입니다. 루트 권한이없고 새 패키지를 설치할 수 없다는 뜻입니다. 확실히 가정 디렉토리에 설치가 가능합니다. 그러나 이식 가능한 스크립트를 만들고 "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-07-28

3
wc -c훌륭하지만 파일에 대한 읽기 권한이 없으면 작동하지 않습니다.
Silas

41

나는 크기를 표시하기 위해 내 자신의 프로그램 (정말 작은)을 작성했습니다. 자세한 정보 : http://fwhacking.blogspot.com/2011/03/bfsize-print-file-size-in-bytes-and.html

일반적인 Linux 도구를 사용하는 가장 깨끗한 두 가지 방법은 다음과 같습니다.

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

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

그러나 파일 크기를 얻기 위해 매개 변수를 입력하거나 출력을 파이프하고 싶지 않으므로 내 bfsize를 사용하고 있습니다.


2
문제 설명의 첫 번째 줄에는 stat가 옵션이 아니며 wc -c가 1 년 넘게 가장 많이 사용 된 답변이므로이 답변의 요점이 무엇인지 잘 모르겠습니다.

22
요점은 구글이 SO 질문을 찾아 나 같은 사람에 stat 있다 그들에 대한 옵션을 선택합니다.
yo

3
저는 wc -c10MB 파일에서 4090msec와에서 "0"msec를 사용 하는 임베디드 시스템에서 작업 stat -c %s중이므로 제시된 정확한 질문에 대답하지 않아도 대체 솔루션을 사용하는 것이 도움이된다는 데 동의합니다.
Robert Calhoun 2013 년

3
"stat -c"는 이식 가능하지 않으며 Linux에서와 같이 MacOS에서 동일한 인수를 허용하지 않습니다. "wc -c"는 대용량 파일의 경우 매우 느립니다.
Orwellophile 2013 년

2
통계도 이식 할 수 없습니다. 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
맥 OS X에서 brew install coreutilsgdu -b같은 효과를 달성 할 수
호세 알반

1
wc결과를 제공하기 전에 전체 파일을 읽어야 하기 때문에이 방법을 선호 du합니다.
CousinCocaine

2
POSIX는 언급 du -b에서 완전히 다른 맥락에서 du근거 .
Palec

lstat호출 만 사용 하므로 성능이 파일 크기에 의존하지 않습니다. 보다 짧지 stat -c '%s'만 덜 직관적이며 폴더에 대해 다르게 작동합니다 (내부 각 파일의 크기 인쇄).
Palec

FreeBSDdudu -A -B1 는를 사용하여 가까워 질 수 있지만 여전히 1024B 블록의 배수로 결과를 인쇄합니다. 바이트 수를 인쇄하도록 관리하지 않았습니다. 심지어 설정 BLOCKSIZE=1512B 블록이 다음 사용되기 때문에 environemnt에는 도움이되지 않습니다.
Palec

13

마지막으로 ls 및 bash 배열 확장을 사용하기로 결정했습니다.

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

별로 좋지는 않지만 적어도 하나의 fork + execve 만 수행하고 보조 프로그래밍 언어 (perl / ruby ​​/ python / whatever)에 의존하지 않습니다.


제쳐두고- '-ln'의 'l'은 필요하지 않습니다. '-n'은 '-ln'과 정확히 동일합니다
금지됨

아니, 그렇지 않습니다. 출력을 비교하십시오.

1
포터블 ls -ln FILE | { read _ _ _ _ size _ && echo "$size"; }은 파이프 라인의 두 번째 단계에서 포크가 필요하지 않다고 추측 할 수 있습니다. 내장 기능 만 사용하기 때문입니다.하지만 Bash 4.2.37은 Linux에서 두 번 포크합니다 (여전히 하나만 execve).
Palec

read _ _ _ _ size _ <<<"$(exec ls -ln /usr/bin/wc)" && echo "$size"단일 포크 및 단일 exec에서 작동하지만 here-string에 임시 파일을 사용합니다. here-string을 POSX 호환 here-document 로 대체하여 이식 가능하게 만들 수 있습니다 . BTW exec는 하위 셸에 있습니다. 이것이 없으면 Bash는 서브 쉘에 대해 하나의 포크를 수행하고 내부에서 실행되는 명령에 대해 다른 하나를 수행합니다. 이 답변에서 제공하는 코드의 경우입니다. 너무.
Palec

1
-l존재하면은 불필요 -n합니다. POSIX ls맨 페이지 인용 : -n: -l(ell) 옵션을 설정하되 파일의 소유자 또는 그룹을 작성할 때 각각 사용자 또는 그룹 이름이 아닌 파일의 숫자 UID 또는 GID를 작성합니다. 사용 안 함 -C, -m-x옵션.
Palec

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를 사용하는 것보다 bash 에서 분기 를 수행 하지 않고 작업을 수행하는 요점을 완전히 놓친 것 같습니다.
Orwellophile

8

BSD는 statGNU coreutils와 다른 옵션을 가지고 있지만 비슷한 기능을 가지고 있습니다.

stat -f %z <file name> 

이것은 macOS (10.12에서 테스트 됨), FreeBSD , NetBSDOpenBSD에서 작동 합니다.


하지만 솔라리스에는 stat유틸리티 가 전혀 없습니다 .
Palec

6

ls -n출력을 처리 할 때 잘못 이식 할 수있는 쉘 배열의 대안으로 유일한 배열을 형성하고 표준 쉘의 유일한 지역 변수 인 위치 인수를 사용할 수 있습니다. 스크립트 또는 함수에 대한 원래 인수를 유지하려면 함수에서 위치 인수 덮어 쓰기를 래핑합니다.

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

ln -dn현재 IFS환경 변수 설정 에 따라 의 출력을 분할하고 위치 인수에 할당하고 다섯 번째 인수를 에코합니다. 는 에서와 달리 -d디렉토리가 올바르게 처리되고 -n사용자 및 그룹 이름을 확인할 필요가 없음을 보장합니다 -l. 또한 공백이 포함 된 사용자 및 그룹 이름은 이론적으로 예상되는 줄 구조를 깨뜨릴 수 있습니다. 일반적으로 허용되지 않지만 이러한 가능성은 여전히 ​​프로그래머를 멈추고 생각하게 만듭니다.


5

findGNU fileutils에서 사용 하는 경우 :

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

안타깝게도의 다른 구현은 find일반적으로 -maxdepth, 또는 -printf. 이것은 예를 들어 Solaris 및 macOS의 경우입니다 find.


참고로 maxdepth는 필요하지 않습니다. 로 다시 작성할 수 있습니다 size=$(test -f filename && find filename -printf '%s').
Palec 2014

@Palec : 는 재귀적인 -maxdepth것을 방지하기위한 것입니다 find( statOP가 교체해야하는 것이 아니기 때문에). 귀하의 find명령은 누락 -name하고, test명령은 필요하지 않습니다.
추후 공지가있을 때까지 일시 중지되었습니다.

@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

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이 있으면 사용하십시오. 그렇지 않으면 ls with awk가 차선책입니다. stat가 없거나 찾기가 GNU 찾기가 아니기 때문입니다.


-3

내가 사용한 솔라리스에는 하나 이상의 파일의 크기를 요청하면 이름이없는 전체 크기 만 반환되므로 두 번째 파일로 / dev / null과 같은 빈 파일을 포함합니다.

예 : 명령 fileyouwant / dev / null

ls / wc / etc에서 작동하는 크기 명령을 기억할 수 없습니다. 불행히도 테스트 할 솔라리스 상자가 없습니다.


-4

리눅스에서 사용할 수 있습니다 du -h $FILE. 솔라리스에서도 작동합니까?


1
실제로 단위를 변환 할 수 있지만 이것은 파일 데이터 크기 ( "겉보기 크기") 대신 디스크 사용량을 표시합니다.
Palec

-7

du -ks | awk '{print $ 1 * 1024}'. 그게 효과가있을 수 있습니다.


1
파일 데이터 크기 ( "명백한 크기") 대신 디스크 사용량을 표시합니다.
Palec
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.