Я ищу элегантный однострочный (например, awk
), который будет сокращать строку пути Unix, используя первый символ каждого родительского / промежуточного уровня, но полное базовое имя. Проще показать на примерах:
/path/to/file
→/p/t/file
/tmp
→/tmp
/foo/bar/.config/wizard_magic
→/f/b/./wizard_magic
/foo/bar/.config/wizard_magic
→/f/b/.c/wizard_magic
В свете хороших моментов @ MichaelKjörling и @ChrisH ниже, этот пример показывает, как мы могли бы показать первые два символа, когда первый символ - точка.
/f/b/.c/wizard_magic
. Точка часто настолько распространена в определенном каталоге, что является очень маленькой подсказкой, куда вы должны смотреть..
обычно означает «текущий каталог». То/f/b/./wizard_magic
же самое,/f/b/wizard_magic
что и элемент path./
сжимается в пустой элемент path.Ответы:
Для этого тестового файла:
Сокращения могут быть получены с помощью этого кода awk:
Edit1: использование двух символов для имен точек
Эта версия сокращает имена каталогов до одного символа, за исключением имен, которые начинаются с
.
которых сокращаются до двух символов:Как это работает
-F/
Это говорит awk использовать косую черту в качестве разделителя полей на входе.
for (i=1;i<NF;i++) $i=substr($i,1,1)
Он зацикливается на каждом поле, кроме последнего, и заменяет его только первым символом.
EDIT1: в пересмотренной версии мы делаем длину подстроки 2, когда поле начинается с
.
.1
Это говорит awk распечатать исправленную строку.
OFS=/
Это говорит awk использовать косую черту в качестве разделителя полей на выходе.
источник
‥
разделителя:awk -F/ '{for (i=1;i<NF;i++) $i=substr($i,1,1+($i~/^[.]/))(i==1||length($i)<2?"":"‥")} 1' OFS=/ <<<$PWD
дает:/foo/bar/.config/wizard_magic
→/f‥/b‥/.c‥/wizard_magic
Довольно просто в sed (при условии, что в именах файлов нет новых строк):
Менее просто в awk, потому что в нем отсутствуют обратные ссылки (кроме Gawk, но с неуклюжим синтаксисом):
В зш (с путем в
$full_path
):источник
\1
в строке замены это означает ссылку на захват группы в шаблоне. Обратная ссылка - это обратная ссылка независимо от того, где вы ее используете.Вы можете сделать это так:
и вот
sed
:это довольно близко к тому, чтобы делать все то же самое, что функция делает ниже. он не сокращается с тильдами и не вставляет в
$PWD
голову для начального не косой черты, как функция (и фактически никогда не печатает начальную косую черту), но это может быть обработано впоследствии. он обрабатывает компоненты с нулевым путем и одноточечные, и отсеивает..
случаи.по тому же
man
пути, что иcd
выше, он печатает:он также напечатает одну или две дополнительные начальные точки для каждого компонента пути, который начинается с такового, а не просто одну или две точки.
Вы спрашивали о том, чтобы сделать больше, чем один символ для компонента пути, начинающегося с
.
. чтобы сделать это, я решил, что каждый компонент в любом случае будет нуждаться в индивидуальном внимании, и, поскольку мне было любопытно, я попробовал свои силы в разработке канонического пути без каталога изменений. после некоторой проб и ошибок я в итоге решил, что единственный способ сделать это правильно - это сделать это дважды - вперед и назад:таким образом, он никогда не изменяет каталог и не пытается подтвердить существование какого-либо компонента пути, но он сжимает повторяющиеся
/
разделители и полностью удаляет компоненты, состоящие из/./
одной точки, и соответствующим образом обрабатывает/../
компоненты с двумя точками.Когда
$IFS
для некоторого непробельного символа задано значение , последовательность из двух или более$IFS
символов приведет к появлению одного или нескольких пустых полей. поэтому множественные последовательные слэши работают с нулевыми аргументами. То же самое верно для главного$IFS
героя. и поэтому приset -- $1
разбиении, если полученное значение$1
равно нулю, оно начинается с косой черты, иначе,${1:+$PWD}
если оно не равно нулю, то я вставляю$PWD
. другими словами, если первый аргумент не начинается с косой черты, он будет$PWD
добавлен. это настолько близко, насколько это касается проверки пути .в противном случае первый
for
цикл рекурсивно инвертирует порядок компонентов пути, например:... при этом он игнорирует любые одноточечные или нулевые компоненты, и для
..
этого делает ...... второй проход отменяет этот эффект, и при этом он сжимает каждый компонент либо в 2 точки + символ , либо в 1 точку + символ , либо в символ .
поэтому он должен идти по каноническому пути независимо от существования.
Я добавил / вычитал немного во второй цикл. теперь это происходит
set
реже (только один раз для каждого[!./]*
компонента) иcase
большую часть времени выполняет оценку шаблонов коротких замыканий (благодаря вышеупомянутому шаблону) , а также включает в себя оценку соответствия по хвостовому вызову~
. если все или начальная часть (разделенная на целые компоненты) окончательно канонического пути могут совпадать~
, совпадающий бит будет удален и~
будет заменен литерал . чтобы сделать это, я должен был сохранить полную копию пути вместе с сокращенным (поскольку сопоставление сокращенного пути,~
вероятно, не очень помогло бы) , и поэтому это сохраняется$3
. последнийwhile
ветви петли выполняется только тогда , когда~
подобран как подмножество$3
.если вы запустите его с
set -x
включенной трассировкой, вы можете посмотреть, как он работает.источник
«Тусклый» Zsh тема от Oh My Zsh содержит Perl фрагмент кода , чтобы сделать это , что имеет поддержку Unicode:
источник
Вы хотите иметь короткое имя или использовать его для командной строки?
Для командной строки у меня есть следующие предложения:
Разве завершение файла в вашей оболочке не поможет?
Иногда вам везет и не нужно делать что-то особенное
Если у вас есть только каталоги, которые вас интересуют, вы можете использовать псевдонимы:
Или вы можете установить переменные для ваших любимых директ
Я думаю, что эти варианты имеют больше смысла, чем пытаться решить это с помощью функции, определенной в .bashrc (или .profile), как
и вызывая эту функцию x с пробелами между вашими буквами:
источник