Портативный способ получить размер файла (в байтах) в оболочке?

StackOverflow https://stackoverflow.com/questions/1815329

  •  06-07-2019
  •  | 
  •  

Вопрос

В 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 команды, чтобы сделать то же самое?

Это было полезно?

Решение

wc -c < filename (сокращение от количества слов, -c печатает счетчик байтов) - переносимый, решение POSIX . Только формат вывода может быть неодинаковым на разных платформах, так как некоторые пробелы могут быть добавлены (что имеет место для Solaris).

Не пропускайте перенаправление ввода. Когда файл передается в качестве аргумента, имя файла печатается после количества байтов.

Я беспокоился, что это не сработает для двоичных файлов, но работает нормально как в Linux, так и в Solaris. Вы можете попробовать это с wc -c < /usr/bin/wc. Более того, утилиты POSIX гарантированно обрабатываются двоичные файлы , если явно не указано иное.

Другие советы

В итоге я написал свою собственную (очень маленькую) программу для отображения только размера. Дополнительную информацию можно получить здесь: http: // fwhacking .blogspot.com / 2011/03 / bfsize-принт-размер файла в байтах-and.html-

Два наиболее чистых способа, на мой взгляд, с помощью обычных инструментов Linux:

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

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

Но я просто не хочу набирать параметры или передавать данные только для того, чтобы получить размер файла, поэтому я использую свой собственный bfsize.

Несмотря на то, что du обычно печатает использование диска, а не фактический размер данных, GNU coreutils <=> может распечатать файл " видимый размер " в байтах:

du -b FILE

Но это не будет работать под BSD, Solaris, macOS, ...

В конце концов я решил использовать ls и расширение массива bash:

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

это не очень приятно, но, по крайней мере, он выполняет только 1 fork + execve, и он не зависит от вторичного языка программирования (perl / ruby / python / что угодно)

Кроссплатформенное самое быстрое решение (использует только один fork () для ls , не пытается подсчитывать реальные символы, не вызывает ненужных awk, perl и т. д.).

Протестировано на MacOS, Linux - может потребоваться незначительная модификация для Solaris:

__ln=( $( ls -Lon "$1" ) )
__size=${__ln[3]}
echo "Size is: $__size bytes"

При необходимости упростите аргументы ls и настройте смещение в $ {__ ln [3]}.

Примечание: будет следовать символическим ссылкам.

BSD имеют stat с опциями, отличными от основных для GNU, но схожими возможностями.

stat -f %z <file name> 

Это работает в macOS (протестировано 10.12), FreeBSD , NetBSD и OpenBSD .

Если вы используете find из файловой утилиты GNU:

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

К сожалению, другие реализации -maxdepth обычно не поддерживают ни -printf, ни <=>. Это касается, например, Solaris и macOS <=>.

При обработке вывода ls -n, в качестве альтернативы плохо переносимым массивам оболочки, вы можете использовать позиционные аргументы, которые образуют единственный массив и являются единственными локальными переменными в стандартной оболочке. Оберните перезапись позиционных аргументов в функции, чтобы сохранить исходные аргументы в вашем скрипте или функции.

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

Это разделяет вывод ln -dn в соответствии с текущими настройками переменной среды IFS, назначает его позиционным аргументам и повторяет пятый. -d обеспечивает правильную обработку каталогов, а -n гарантирует, что имена пользователей и групп не нужно разрешать, в отличие от -l. Кроме того, имена пользователей и групп, содержащие пробелы, теоретически могут нарушать структуру ожидаемой линии; они обычно запрещены, но эта возможность все еще заставляет программиста задуматься.

Вы можете использовать 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~

Ваш первый пример Perl не выглядит для меня необоснованным.

Именно по таким причинам я перешел от написания сценариев оболочки (в bash / sh и т. д.) к написанию всех, кроме самых простых сценариев в Perl. Я обнаружил, что мне нужно запускать Perl для конкретных требований, и по мере того, как я делал это все больше и больше, я понял, что написание скриптов на Perl, вероятно, было более мощным (с точки зрения языка и широкого спектра библиотек, доступных через < a href = "http://www.cpan.org" rel = "nofollow noreferrer"> CPAN ) и более эффективный способ добиться того, чего я хотел.

Обратите внимание, что другие языки сценариев оболочки (например, python / ruby), несомненно, будут иметь аналогичные возможности, и вы можете оценить их для своих целей. Я обсуждаю только Perl, так как это язык, который я использую и с которым я знаком.

если у вас есть Perl в Solaris, используйте его. В противном случае, ls с awk - ваша следующая лучшая ставка, так как у вас нет stat или ваша находка не является GNU find.

В Solaris, который я использовал, есть хитрость: если вы запрашиваете размер более чем одного файла, он возвращает только общий размер без имен - поэтому включите пустой файл, такой как /dev/null, в качестве второго файла:

например, командный файл вы хотите /dev/null

Я не могу вспомнить, с какой командой size это работает для ls / wc / etc - к сожалению, у меня нет коробки solaris для ее тестирования.

в Linux вы можете использовать du -h $FILE, это тоже работает на солярисе?

Вы пробовали du -ks | awk '{напечатать $1*1024}'.Это может просто сработать.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top