#linux #bash #shell #unix #ps1
Вопрос:
Я знаю, что могу сделать это, чтобы отразить в значении только последние 2 каталога PS1
.
PS1=${PWD#"${PWD%/*/*}/"}#
но допустим , у нас есть имя каталога, которое действительно запутано и сократит мое рабочее пространство, например
T-Mob/2021-07-23--07-48-49_xperia-build-20191119010027#
или
2021-07-23--07-48-49_nokia-build-20191119010027/T-Mob#
это последние 2 каталога перед prompt
Я хочу установить условие , если длина каталога любого из последних 2 каталогов превышает пороговое значение, например, 10 символов, сократите имя с 3-мя и 3-мя последними символами каталога (ов), длина которого превышает 10, например
2021-07-23--07-48-49_xperia-build-20191119010027 amp;
2021-07-23--07-48-49_nokia-build-20191119010027
оба gt 10 будут сокращены до 202*027
amp; PS1 соответственно
T-Mob/202*027/# for T-Mob/2021-07-23--07-48-49_xperia-build-20191119010027#
и 202*027/T-Mob# for 2021-07-23--07-48-49_nokia-build-20191119010027/T-Mob#
Быстрый 1 лайнер, чтобы это сделать ? Я не могу опубликовать это в комментариях, поэтому обновляю здесь. Ссылка на ответ Хоакина ( thx J)
PS1=''`echo ${PWD#"${PWD%/*/*}/"} | awk -v RS='/' 'length() <=10{printf $0"/"}; length()>10{printf "%s*%s/", substr($0,1,3), substr($0,length()-2,3)};'| tr -d "n"; echo "#"`''
смотрите ниже o/p
/root/my-applications/bin # it shortened as expected
my-*ons/bin/#cd - # going back to prev.
/root
my-*ons/bin/# #value of prompt is the same but I am in /root
Комментарии:
1. Зачем вам однострочник? Разве читабельность (и, следовательно, ремонтопригодность) не важнее краткости?
2.Кроме того, не помечайте свои вопросы знаком
awk
илиsed
, если только ваш вопрос не касаетсяawk
илиsed
. Если вы просто думаете, что это инструменты, которые кто-то может использовать для создания ответа, ваш вопрос не об этих инструментах-отметьтеunix
, если вам нужны ответы, использующие стандартные инструменты UNIX. Тем не менее, для чего-то вроде печати приглашения-это происходит снова и снова с очень небольшим промежутком времени между вызовами-вы не хотите использовать внешние команды (как awk, так и sed) исключительно по соображениям производительности; создание подпроцессов-одна из самых медленных вещей, которые может сделать оболочка.3. @user1874594: Я предлагаю вам написать функцию, которая создает строку каталога, и использовать эту функцию в своем
PS1
. Это проще в отладке и обслуживании.4. @user1934428, для использования функции в вашей PS1 с помощью подстановки команд требуется разветвление вложенной оболочки. Это медленнее, чем выполнение задания в
PROMPT_COMMAND
(при условии, конечно, что вашPROMPT_COMMAND
код написан, чтобы избежать вложенных оболочек).5. @CharlesDuffy: Правильно, но поскольку эта функция выполняется только при выводе приглашения (т. Е. в масштабе времени взаимодействия с пользователем), по крайней мере, создание дочернего процесса-это не то, о чем я бы беспокоился.
Ответ №1:
Однострочный вариант-это в основном всегда неправильный выбор. Пишите код, чтобы он был надежным, читаемым и доступным для обслуживания (и, для того, что часто вызывается или в узком цикле, чтобы быть эффективным), а не быть кратким.
При условии наличия bash 4.3 или более поздней версии:
# Given a string, a separator, and a max length, shorten any segments that are
# longer than the max length.
shortenLongSegments() {
local -n destVar=$1; shift # arg1: where do we write our result?
local maxLength=$1; shift # arg2: what's the maximum length?
local IFS=$1; shift # arg3: what character do we split into segments on?
read -r -a allSegments <<<"$1"; shift # arg4: break into an array
for segmentIdx in "${!allSegments[@]}"; do # iterate over array indices
segment=${allSegments[$segmentIdx]} # look up value for index
if (( ${#segment} > maxLength )); then # value over maxLength chars?
segment="${segment:0:3}*${segment:${#segment}-3:3}" # build a short version
allSegments[$segmentIdx]=$segment # store shortened version in array
fi
done
printf -v destVar '%sn' "${allSegments[*]}" # build result string from array
}
# function to call from PROMPT_COMMAND to actually build a new PS1
buildNewPs1() {
# declare our locals to avoid polluting global namespace
local shorterPath
# but to cache where we last ran, we need a global; be explicit.
declare -g buildNewPs1_lastDir
# do nothing if the directory hasn't changed
[[ $PWD = "$buildNewPs1_lastDir" ]] amp;amp; return 0
shortenLongSegments shorterPath 10 / "$PWD"
PS1="${shorterPath}$"
# update the global tracking where we last ran this code
buildNewPs1_lastDir=$PWD
}
PROMPT_COMMAND=buildNewPs1 # call buildNewPs1 before rendering the prompt
Обратите внимание, что printf -v destVar %s "valueToStore"
это используется для записи в переменные на месте, чтобы избежать дополнительных затрат на производительность var=$(someFunction)
. Аналогично, мы используем функцию bash 4.3 namevars, доступную с local -n
помощью или declare -n
, чтобы разрешить параметризацию имен переменных назначения без риска для безопасности eval
.
Если вы действительно хотите, чтобы эта логика применялась только к двум последним именам каталогов (хотя я не понимаю, почему это было бы лучше, чем применять ее ко всем из них), вы можете сделать это достаточно легко:
buildNewPs1() {
local pathPrefix pathFinalSegments
pathPrefix=${PWD%/*/*} # everything but the last 2 segments
pathSuffix=${PWD#"$pathPrefix"} # only the last 2 segments
# shorten the last 2 segments, store in a separate variable
shortenLongSegments pathSuffixShortened 10 / "$pathSuffix"
# combine the unshortened prefix with the shortened suffix
PS1="${pathPrefix}${pathSuffixShortened}$"
}
…добавление оптимизации производительности, которая перестраивает PS1 только при изменении каталога на эту версию, оставлено в качестве упражнения для читателя.
Комментарии:
1. Спасибо, Чарльз. Вы абсолютно правы с точки зрения практики кодирования — если вас нужно понять, я не могу писать такие вещи, как стены Сфинкса, и навсегда оставляю ppl в догадках. Это замечательно и льется, как жемчужины из бутылки. Но чего бы ни стоил уход за
PS1
собой во время работы , я просто хотел посмотреть, можно ли его убрать, вставив несколько дополнительных строк в мою~/.profile
2. Вы должны быть в состоянии вставить вышесказанное
~/.bashrc
(я бы не стал вставлять его.profile
по нескольким причинам:.profile
также используется оболочками, не относящимися к bash, в то время как вышеописанный код относится к bash, и он вызывается только для оболочек входа, а не для интерактивных оболочек, запускаемых как дочерние элементы этих оболочек входа).3. да, я была ‘обстрел’, то и часто, но редко обращал ИМП на производительность, потому что если ваше дело с миллионами записей, где МС сэкономленное время добавляет в прямом смысле , его небольшой стоимости, но ваш «Программирование манерами», что делает программирование (супер) человек заслуживают внимания даже в качестве подхода ака шаблон для будущих
shell
вкладыши и буду иметь в виду
Ответ №2:
Вероятно, не лучшее решение, но быстрое решение с использованием awk:
PS1=`echo ${PWD#"${PWD%/*/*}/"} | awk -v RS='/' 'length()<=10{printf $0"/"}; length()>10{printf "%s*%s/", substr($0,1,3), substr($0,length()-2,3)};'| tr -d "n"; echo "#"`
Я получил эти результаты с вашими примерами:
T-Mob/202*027/#
202*027/T-Mob/#
Комментарии:
1. Смотрите сравнение производительности наших двух ответов на ideone.com/3ykAWR
2. …конечно, это немного несправедливо из-за оптимизации «только повторный запуск, если PWD изменится» в моей, которая закорачивает большую часть кода. ideone.com/TNc2Pr является повторным запуском с этой оптимизацией (благодаря неясностям онлайн-песочниц оба ответа имеют худшую производительность, но общий характер отношений между ними сохраняется-замены команд, конвейеры и запуск новых копий
awk
-все это дорого).3. @Joaquin, это динамически меняется, когда вы записываете компакт-диски на другие dir?
4. @pynexj, заключите правую часть назначения в одинарные кавычки, чтобы предотвратить вызов подстановки команды только один раз во время назначения, а затем ее следует оценивать при отображении запроса, а не при выполнении приведенного выше кода.
5. не динамично …. нужно запускать каждый раз. Это то, что я использовал на основе вышеупомянутого fb, описанного в Q