Команда dirname(1) з беллабсівської рісьóрч Unix v8 (1985):
$ cat usr/bin/dirname
# @(#)dirname.sh 1.2
expr \
${1-.}'/' : '\(/\)[^/]*/$' \
\| ${1-.}'/' : '\(.*[^/]\)//*[^/][^/]*//*$' \
\| .
На жаль, Торвальдсу тоді було лише 16 років і ґіта він AT&T подарувати
не міг, тому хто був автором іммортальних рядків, залишається
невідомим.
Загалом, v8 продвжувала традицію 'все що може бути скриптом шелóвим
має їм бути', наприклад /bin/true сяяв 0755 з розміром 0 байт.
Багато хто зі світу віндюка досі не розуміє чому навіть сучасні
лайнакси мало використовують імена хфайлів з пробілами. Річ у тому, що
останні вийнашли тільки ув 2000х роках, а до того люди ніколи не
умивалися і їли
сало:
$ sh usr/bin/dirname 'foo bar'
expr: syntax error: unexpected argument ‘bar/’
Ви часто використовуєте ютіліту expr(1)? Я чомусь думав вона є
builtin, але ніхто з шелів її не чіпає. Гадаю, про неї забули всі
хто про неї знав, як тільки з'явилася підтримка орифметичного
ікспаншону ув $(( … ))
.
Оператор :
став для мене новиною. STRING : REGEX
робить пошук за
взірцем, а якщо regex має субікспрешона \( … \)
, то ютіліта друкує
його ув стилі 'grep -o'.
Це видається корисним, але насправді товку від того є небагато.
Можна написати аналога basename(1), але навіщо?
$ expr /$SHELL : '.*/\([^/]*\)$'
bash
Порахувати довжину рядка:
$ expr foobar : '.*'
6
Надрукувати ув лайнаксі регіона таймзони:
$ expr `realpath /etc/localtime` : '.*/\(.*\)/.*$'
Europe
Таке. Перевірити рядок на суфікса:
$ q=foo.txt
$ expr $q : '.*\.txt$'
7
але ідіома
$ [ "${q##*.}" = 'txt' ]
є більш відомою і викличе меньше питань.
Сучасні dirname(1), звичайно, шелóвими скриптами не бувають. Вони або
використовують позіксну dirname(3), або пишуть криву (але свою, як
coreutils) хфункцію пошуку '/'.