№ 18. Вывод содержимого каталогов
Нам всегда казался бессмысленным один из аспектов команды ls: для каталогов она либо выводит список содержащихся в них файлов, либо показывает количество блоков по 1024 байта, необходимых для хранения данных. Ниже показано, как выглядит типичный элемент списка, возвращаемого командой ls −l:
drwxrwxr-x·· 2 taylor·· taylor·· 4096 Oct 28 19:07 bin
Но в этой информации мало проку! В действительности нам хотелось бы знать, сколько файлов находится в каталоге. Именно это делает сценарий в листинге 2.12. Он генерирует многоколоночный список файлов и каталогов, показывая для файлов их размеры, а для каталогов — количество содержащихся в них записей.
Листинг 2.12.Сценарий formatdir для получения более информативных списков каталогов
··#!/bin/bash
··# formatdir — выводит содержимое каталога в дружественном и информативном виде
··# Обратите внимание: необходимо, чтобы "scriptbc" (сценарий № 9) находился
··#·· в одном из каталогов, перечисленных в PATH, потому что он неоднократно
··#·· вызывается в данном сценарии.
··scriptbc=$(which scriptbc)
··# Функция для преобразования размеров из KB в KB, MB или GB для
··#·· большей удобочитаемости вывода
··readablesize()
··{
····if [$1 −ge 1048576]; then
······echo "$($scriptbc −p 2 $1 / 1048576)GB"
····elif [$1 −ge 1024]; then
······echo "$($scriptbc −p 2 $1 / 1024)MB"
····else
······echo "${1}KB"
····fi
··}
··#################
··## КОД ОСНОВНОГО СЦЕНАРИЯ
··if [$# −gt 1]; then
····echo "Usage: $0 [dirname]" >&2
····exit 1
··elif [$# −eq 1]; then # Указан определенный каталог, не текущий?
····cd "$@"················# Тогда перейти в него.
····if [$? -ne 0]; then # Или выйти, если каталог не существует.
······exit 1
····fi
··fi
··for file in *
··do
····if [-d "$file"]; then
······size=$(ls "$file" | wc −l | sed 's/[^[: digit: ]]//g')
······if [$size −eq 1]; then
········echo "$file ($size entry)|"
······else
········echo "$file ($size entries)|"
······fi
····else
······size="$(ls −sk "$file" | awk '{print $1}')"
······echo "$file ($(readablesize $size))|"
····fi
··done | \
····sed 's/ /^^^/g' | \
····xargs −n 2 | \
····sed 's/\^\^\^/ /g' | \
····awk−F\| '{ printf "%-39s %-39s\n", $1, $2 }'
··exit 0
Одним из наиболее интересных элементов сценария является функция readablesize
, которая принимает число в килобайтах и выводит килобайты, мегабайты или гигабайты, в зависимости от наиболее подходящей единицы измерения. Например, для файла очень большого размера она выведет 2.08GB вместо 2,083,364KB. Обратите внимание, что readablesize вызывается с применением конструкции $()
:
echo "$file ($(readablesize $size))|"
Подоболочки автоматически наследуют все функции, объявленные в родительской оболочке, поэтому подоболочка, запущенная конструкцией $(), получит доступ к функции readablesize. Очень удобно.
Ближе к началу сценария
проверяется, был ли указан какой-то другой каталог, отличный от текущего, и затем производится смена текущего рабочего каталога выполняющегося сценария с помощью простой команды cd.
Основная логика сценария занимается организацией вывода в две колонки, выровненные по вертикали. Одна из проблем, возникающих при этом, состоит в том, что пробелы в потоке вывода нельзя просто заменить символами перевода строки, потому что имена файлов и каталогов сами могут содержать пробелы. Чтобы решить эту проблему, сценарий в
сначала замещает каждый пробел последовательностью из трех «крышек» (^^^). Затем с помощью команды xargs объединяет строки попарно, чтобы каждая пара строк превратилась в одну, разделенную вертикальной чертой на два поля. Наконец, в
вызывается команда awk для вывода полей с требуемым выравниванием.
Читать дальше