Bash 对于多行提示,打印第一行与在PS1字符串中插入相比有什么缺点吗?

Bash 对于多行提示,打印第一行与在PS1字符串中插入相比有什么缺点吗?,bash,Bash,基本上,PS1提示符设置如下 (假设所有变量和函数都能正确退出) vs做这件事 PROMPT_COMMAND='\ ret=$?;\ p_colorSetup;\ printf "%b" "[${P_TIME}$(date +%H:%M)${P_RES}]$(p_multiPlex)[${P_NAME}$(id -un)${P_RES}@${P_HOST}$(hostname -s)${P_RES}]: ${P_DIR}$(pwd | sed -e "s#${HOME}#~#" )${P_RES

基本上,PS1提示符设置如下

(假设所有变量和函数都能正确退出)

vs做这件事

PROMPT_COMMAND='\
ret=$?;\
p_colorSetup;\
printf "%b" "[${P_TIME}$(date +%H:%M)${P_RES}]$(p_multiPlex)[${P_NAME}$(id -un)${P_RES}@${P_HOST}$(hostname -s)${P_RES}]: ${P_DIR}$(pwd | sed -e "s#${HOME}#~#" )${P_RES} \n";\
PS1="$(p_returnColor ${ret}) \\$ "'
我很好奇用这种方法和用另一种方法相比是否有什么好处/缺点。只要我正确地避开了所有问题,我似乎不会在键入或查看历史记录时遇到任何包装问题


在这种情况下,是否有任何理由使用一个或另一个?

我将定义一个函数,从
提示符\u命令
调用该函数,这使得在多行中引用和拆分代码更加简单。这使得阅读、调试和修改更容易

make_prompt () {
  ret=$?
  p_colorSetup
  PS1="[\[$P_TIME\]\A\[$P_RES\]]"
  PS1+=$(p_multiPlex)
  PS1+="[\[$P_NAME\]\u\[$P_RES\]@\[${P_HOST}\]\h\[${P_RES}\]]: "
  PS1+="\[${P_DIR}\]\w\[${P_RES}\]\n"
  PS1+=$(p_returnColor ${ret})
  PS1+=' \$'
}

PROMPT_COMMAND=make_prompt

我将定义一个从
PROMPT_COMMAND
调用的函数,这使得在多行中引用和拆分代码更加简单。这使得阅读、调试和修改更容易

make_prompt () {
  ret=$?
  p_colorSetup
  PS1="[\[$P_TIME\]\A\[$P_RES\]]"
  PS1+=$(p_multiPlex)
  PS1+="[\[$P_NAME\]\u\[$P_RES\]@\[${P_HOST}\]\h\[${P_RES}\]]: "
  PS1+="\[${P_DIR}\]\w\[${P_RES}\]\n"
  PS1+=$(p_returnColor ${ret})
  PS1+=' \$'
}

PROMPT_COMMAND=make_prompt

您必须确保Bash能够计算提示的长度,即可打印字符的数量。如果你打印了一些东西,Bash不知道。如果编辑多行命令,Bash会弄乱提示

在大多数情况下,最好使用Bash的参数扩展而不是
sed

我认为最好使用PROMPT_命令来定义一些变量,这些变量将在
PS1
中引用。为了可读性,最好编写一个函数,用于构建
PS1

ps1 ()
{
  local bold="\[\e[1m\]"
  local black="\[\e[30m\]"
  local red="\[\e[31m\]"
  local green="\[\e[32m\]"
  local yellow="\[\e[33m\]"
  local blue="\[\e[34m\]"
  local magenta="\[\e[35m\]"
  local cyan="\[\e[36m\]"
  local reset="\[\e[m\]"

  # terminal title
  if [ "$TERM" = xterm ]; then
    echo -n '\[\e]0;\h${PS1EXIT:+ [$PS1EXIT]}\a\]'
  fi

  # visible prompt
  echo -n $bold

  # exit code
  echo -n '${PS1EXIT:+'$black'['$red'$PS1EXIT'$black'] }'

  # user @ host
  echo -n $red'\u'$black'@'$magenta'\h'$black':'

  # directory
  echo -n $red'$PS1CLIP'$blue'${PS1DIR////'$black'/'$blue'}'

  # command number
  #echo -n $black':'$yellow'\!'

  # prompt char
  echo -n $black'\$'

  # reset colors
  echo $reset' '
}

export PS1=$(ps1)

unset ps1
我做了一些奇特的快速着色和长度剪裁:

export PS1_MAXDIRLEN=25
我为
PROMPT_COMMAND
创建了一个函数,该函数使用Bash的参数展开设置了一些变量

PROMPT_COMMAND ()
{
  # Exit status
  EXIT_STATUS=$?
  PS1EXIT=${EXIT_STATUS##0}

  # Working directory
  PS1CLIP=${PWD: $((-PS1_MAXDIRLEN))}
  local p=${PS1CLIP:+${PWD: $((-(PS1_MAXDIRLEN-1)))}}
  PS1CLIP=${PS1CLIP:+<}
  PS1DIR=${p:-$PWD}
}

export PROMPT_COMMAND=PROMPT_COMMAND

您必须确保Bash能够计算提示的长度,即可打印字符的数量。如果你打印了一些东西,Bash不知道。如果编辑多行命令,Bash会弄乱提示

在大多数情况下,最好使用Bash的参数扩展而不是
sed

我认为最好使用PROMPT_命令来定义一些变量,这些变量将在
PS1
中引用。为了可读性,最好编写一个函数,用于构建
PS1

ps1 ()
{
  local bold="\[\e[1m\]"
  local black="\[\e[30m\]"
  local red="\[\e[31m\]"
  local green="\[\e[32m\]"
  local yellow="\[\e[33m\]"
  local blue="\[\e[34m\]"
  local magenta="\[\e[35m\]"
  local cyan="\[\e[36m\]"
  local reset="\[\e[m\]"

  # terminal title
  if [ "$TERM" = xterm ]; then
    echo -n '\[\e]0;\h${PS1EXIT:+ [$PS1EXIT]}\a\]'
  fi

  # visible prompt
  echo -n $bold

  # exit code
  echo -n '${PS1EXIT:+'$black'['$red'$PS1EXIT'$black'] }'

  # user @ host
  echo -n $red'\u'$black'@'$magenta'\h'$black':'

  # directory
  echo -n $red'$PS1CLIP'$blue'${PS1DIR////'$black'/'$blue'}'

  # command number
  #echo -n $black':'$yellow'\!'

  # prompt char
  echo -n $black'\$'

  # reset colors
  echo $reset' '
}

export PS1=$(ps1)

unset ps1
我做了一些奇特的快速着色和长度剪裁:

export PS1_MAXDIRLEN=25
我为
PROMPT_COMMAND
创建了一个函数,该函数使用Bash的参数展开设置了一些变量

PROMPT_COMMAND ()
{
  # Exit status
  EXIT_STATUS=$?
  PS1EXIT=${EXIT_STATUS##0}

  # Working directory
  PS1CLIP=${PWD: $((-PS1_MAXDIRLEN))}
  local p=${PS1CLIP:+${PWD: $((-(PS1_MAXDIRLEN-1)))}}
  PS1CLIP=${PS1CLIP:+<}
  PS1DIR=${p:-$PWD}
}

export PROMPT_COMMAND=PROMPT_COMMAND

旁白:那有点可怕。尽量避免性能敏感代码中的命令替换——每个
$(foo)
都是
pipe()
调用、
fork()
wait()
等;使用副作用函数(即,将结果写入名称作为参数传递的变量的函数)效率更高。(好吧,当然,shell提示符通常可能对性能不敏感,但当系统处于负载90时,您试图查找并杀死违规进程时,每一个小小的延迟源都会带来很大的痛苦)。我会定义一个函数并从
提示符_命令调用它,而不是直接嵌入大量代码
PROMPT\u COMMAND=make\u PROMPT
,然后相应地定义
make\u PROMPT(){…}
。@chepner既然每次都要运行,那么这两个函数之间会有什么实际区别吗?@CharlesDuffy您能详细说明一下这些函数的含义吗。我对其中一些术语不太熟悉,如果我理解正确,在bash中如何使用这些术语。@Trel,这些是bash在使用命令替换语法时必须进行的操作系统级调用<代码>fork()
,尤其是相对昂贵的,尤其是在使用common bash for Windows构建时。重点是,最好避免在代码中重复调用不必要的命令替换,这样会很快。旁白:这有点可怕。尽量避免性能敏感代码中的命令替换——每个
$(foo)
都是
pipe()
调用、
fork()
wait()
等;使用副作用函数(即,将结果写入名称作为参数传递的变量的函数)效率更高。(好吧,当然,shell提示符通常可能对性能不敏感,但当系统处于负载90时,您试图查找并杀死违规进程时,每一个小小的延迟源都会带来很大的痛苦)。我会定义一个函数并从
提示符_命令调用它,而不是直接嵌入大量代码
PROMPT\u COMMAND=make\u PROMPT
,然后相应地定义
make\u PROMPT(){…}
。@chepner既然每次都要运行,那么这两个函数之间会有什么实际区别吗?@CharlesDuffy您能详细说明一下这些函数的含义吗。我对其中一些术语不太熟悉,如果我理解正确,在bash中如何使用这些术语。@Trel,这些是bash在使用命令替换语法时必须进行的操作系统级调用<代码>fork()
,尤其是相对昂贵的,尤其是在使用common bash for Windows构建时。重点是,最好避免在重复调用并且预期速度很快的代码中进行不必要的命令替换。所有caps名称都由对系统或shell有意义的变量使用;POSIX名称至少有一个小写字符供应用程序使用。而
echo-n
是未定义的行为--请使用
printf
,如的应用程序用法部分所述,并应引用参数扩展--请参阅。(还有,如果出现提示,您不知道用户将运行什么命令,因此
IFS
的当前值将是什么——这使得引用变得更加重要;如果
IFS='['
,出于某种奇怪的原因,这里的代码将出现各种各样的问题)。@charlesduff我尝试了
IFS='['
并且它对提示符没有影响。请参阅