Оцените вывод команды в цветовом формате

Я использую diff для форматирования строки, включающей переменные цвета tput, и не могу оценить эти переменные без использования команды "evil" eval.

Команда, создающая строку:

output1="$(diff --changed-group-format="\${RED}%=\${CLS}" <(echo -e "${nstr1}") <(echo -e "${nstr2}")|tr -d '\n')"

и выводит это:

[String n${RED}â${CLS}m${RED}è™${CLS}]

Я смотрел и искал другие ответы, но ничего не работает, кроме:

eval echo "${output1}"

Из того, что я прочитал, у меня есть 3 варианта: eval(плохо), непрямое расширение(лучше) и массивы(лучший). Все попытки обхода терпят неудачу. Я бы хотел использовать опцию массива, но я просто не понимаю, как это применимо здесь. Я что-то упускаю?

Я не думаю, что это актуально, но переменные и построение строк, отправляемых в diff, находятся в другом вопросе здесь.


person akovia    schedule 21.12.2015    source источник


Ответы (1)


Вы можете использовать расширение параметра Bash, если хотите обойтись конечным заранее известным набором цветовых кодов:

#!/usr/bin/env bash

# Define the variables containing ANSI color sequences.
RED="$(tput setaf 1)"
CYA="$(tput setaf 6)"
CLS="$(tput sgr0)"

# Sample input string
str='[String n${RED}â${CLS}m${CYA}è™${CLS}]'

# Replace the placeholders with their corresponding variable values.
str=${str//'${RED}'/${RED}}
str=${str//'${CYA}'/${CYA}}
str=${str//'${CLS}'/${CLS}}

# Output the result.
echo "$str"

Этот подход использует тот факт, что аргумент, используемый в расширении параметра Bash, сам подлежит расширению, если только он не заключен в одинарные кавычки:

  • ${<varName>//<search>/<replace>} заменяет все экземпляры <search> на <replace> в значении переменной <varName>.
  • '${RED}', например, из-за того, что он заключен в одинарные кавычки, воспринимается как буквальный поисковый запрос.
  • ${RED}, например, из-за того, что он не заключен в кавычки, перед использованием в качестве термина замены расширяется, поэтому эффективно заменяет буквальное ${RED} на значение переменной ${RED}.

Завернутый в функцию:

printColored() {
  local str=$1
  local RED="$(tput setaf 1)" CYA="$(tput setaf 6)" CLS="$(tput sgr0)"
  str=${str//'${RED}'/${RED}}
  str=${str//'${CYA}'/${CYA}}
  str=${str//'${CLS}'/${CLS}}
  printf '%s\n' "$str"
}

printColored '[String n${RED}â${CLS}m${CYA}è™${CLS}]'

Кстати, я бы переименовал ${CLS} в ${RST} (для «сброса») или что-то подобное, потому что термин «cls» предполагает очистку всего экрана.

person mklement0    schedule 21.12.2015
comment
Я не понимаю, почему это работает, но это работает! Разве полученная строка не идентична? Если это вопрос выполнения движений, я мог бы использовать более короткий заполнитель, верно? Кроме того, у меня уже есть эти переменные глобально, поэтому я не должен был объявлять их здесь локальными, верно? (RED, CYA и т. д.) Наконец, отличный совет по cls, который я правильно понял. - person akovia; 21.12.2015
comment
@akovia: Посмотрите, объясняет ли это мое обновление. Да, вы можете использовать более короткие заполнители. Если вы используете глобальные переменные, вам не нужно объявлять их внутри функции, но для лучшей инкапсуляции вы можете сделать это. - person mklement0; 21.12.2015
comment
Спасибо за расширение объяснения. Это прекрасно работает! - person akovia; 21.12.2015