自定义 bash shell

自定义 bash shell

我想以一种非常具体的方式自定义我的 bash shell,具体到我不知道是否可行。目前,我的 shell 如下所示:

myname@ubuntu /home/myname:
>>

其中 myname 是我的用户名。我使用以下行自定义了 shell ~/.bashrc

PS1='${debian_chroot:+($debian_chroot)}\u@\h `pwd`:\n>> '

当我按下回车键时,发生了以下事情:

myname@ubuntu /home/myname:
>>
myname@ubuntu /home/myname:
>>

与此相反,我希望发生以下情况:

myname@ubuntu /home/myname:
>>
>>

此外,如果我输入一个命令,发生的情况应该是这样的:

myname@ubuntu /home/myname:
>> echo hello
hello
myname@ubuntu /home/myname:
>>

以下情况不应该发生

myname@ubuntu /home/myname:
>>echo hello
hello
>>

这可能吗?如果可以,该怎么做?

更新

感谢 ChrisAga 的回复,我才得以实现我的目标。

以下是脚本

# don't put duplicate lines or lines starting with space in the history.
HISTCONTROL=ignoreboth

customprompt() {
    # the current number of lines in bash history:
    bash_history_size=$(fc -l -1)
    bash_history_size=${bash_history_size%%[^0-9]*}

    # set an initial value to the number of lines
    # in bash history stored from the last time
    # this function was executed. This avoids bugs
    # when running the first command in the current
    # shell session
    if [ -n "$bash_history_lastsize" ]; then
        bash_history_lastsize=0
    fi

    # if the current number of lines in bash history
    # is different from the last number of lines, then
    # we print the user name and the current directory.
    # otherwise, we just print >>
    if [ "${bash_history_size}" != "${bash_history_lastsize}" ]; then
        PS1='\[\033[01;32m\]\u@\h \[\033[00m\]`pwd`:\n>> '
    else
        PS1=">> "
    fi

    # update the last value to the current value
    bash_history_lastsize=${bash_history_size}
}

PROMPT_COMMAND=customprompt

答案1

实际上,在普通的 bash 中有解决方案!

唯一的限制是与 bash 命令历史记录中的重复预防不兼容。因此,如果您不介意 bash 历史记录中有重复项,则可以在 中设置以下内容~/.bashrc

HISTCONTROL=ignorespace

function pprompt {
   local hcount=$(fc -l -1)
   echo ${hcount}
   hcount=${hcount%%[^0-9]*}
   if [ "${hcount}" != "${ocount}" ]; then 
      PS1="\[\e]0;\u@\h: \w\a\]\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w:\[\033[00m\]\n>>"
   else 
      PS1=">>"
   fi
   ocount=${hcount}
}

PROMPT_COMMAND=pprompt

默认情况下HISTCONTROL=ignoreboth,这相当于ignorespace:ignoredups所以您必须更改它。

pprompt函数获取历史记录中的最后一条命令并将其编号与之前存储的值进行比较。如果您只是按下 Enter 键,则数字不会改变,因此如果此数字已更改,我们将 PS1 设置为完整提示,否则,我们将其设置为>>

最后,PROMPT_COMMAND=pprompt让 bash 在回显主提示符 ( $PS1) 之前执行 pprompt。

NB1. 如果你不想显示你的主路径~,你可以用`pwd`替换\w。

NB2. 如果我们可以获得实际的 bash 命令编号(我们可以!#在提示符中显示的命令编号)而不是历史命令编号,我们将获得与历史重复数据删除兼容的解决方案。

答案2

据我所知,您无法使用普通的 bash 来做到这一点。而是必须几乎从头开始实现自己的 shell(不要害怕,我已经做到了,它只需要不到 30 行代码)。

这是代码(custom_shell.sh):

RED='\033[0;31m'                         #Definition of some ASCII colors
WHITE='\033[1;37m'                       #Replace them with whatever color you want

TMP_COMM_BUF="/tmp/custom_shell_buf"     #For temporary storage of commands

if [ "$1" == "e" ]
then 
    printf "${RED}>> ${WHITE}"           #When you just pressed enter
else
    printf  "${RED}$PWD >> ${WHITE} "    #After the execution of some command
fi


exec 3<&1                                #Custom file descriptor
read -u 3 comm_buf                       #Read commands from stdin
echo $comm_buf  > $TMP_COMM_BUF          #Store commands (exec cannot execute multiple commands at once , so we need it)
chmod +x $TMP_COMM_BUF                   #Make it executable
if ! [ -z "$comm_buf" ] 
then
    echo custom_shell.sh >> $TMP_COMM_BUF      #Recover the prompt after the execution ( It's assumed that the name of the file is custom_shell.sh and it's available in the $PATH )
    exec $TMP_COMM_BUF                         #Execute !!!
else
    exec custom_shell.sh e                     #If nothing specified , then just show ">>"
fi

限制:

由于它不能使用 bash 中的行编辑功能,因此您无法使用它Ctrl+C来中断或Ctrl+L清除终端。而且它没有命令完成和 shell 历史记录。

安全注意事项:

由于它使用未加密的文件(/tmp/custom_shell_buf)在执行命令之前存储命令,如果有人在执行阶段之前(第 16 行和第 21 行之间)对其进行篡改,就会导致执行不必要的命令。

所以毕竟,作为一项业余爱好作品它已经足够了,并且也能满足您的需求。而且如果您愿意,您还可以添加更多功能。

如果有人有更好的建议,我很高兴听到。

祝您黑客愉快 ;)

相关内容