登录后tty中的“♦:command not found”

将Lubuntu从12.10升级到13.04后,我遇到了这个问题。

我按Ctrl + Alt + 1 ,输入登录名,密码,等待两秒后得到: ♦: command not found" 。在此消息之后我可以输入命令而没有问题,但它是什么?

 echo $PATH /usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/home/vitaly/bin:/usr/java/jdk1.7.0_17/bin 

我的.bashrc文件是:

 # ~/.bashrc: executed by bash(1) for non-login shells. # see /usr/share/doc/bash/examples/startup-files (in the package bash-doc) # for examples # If not running interactively, don't do anything case $- in *i*) ;; *) return;; esac # don't put duplicate lines or lines starting with space in the history. # See bash(1) for more options HISTCONTROL=ignoreboth # append to the history file, don't overwrite it shopt -s histappend # for setting history length see HISTSIZE and HISTFILESIZE in bash(1) HISTSIZE=1000 HISTFILESIZE=2000 # check the window size after each command and, if necessary, # update the values of LINES and COLUMNS. shopt -s checkwinsize # If set, the pattern "**" used in a pathname expansion context will # match all files and zero or more directories and subdirectories. #shopt -s globstar # make less more friendly for non-text input files, see lesspipe(1) [ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)" # set variable identifying the chroot you work in (used in the prompt below) if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then debian_chroot=$(cat /etc/debian_chroot) fi # set a fancy prompt (non-color, unless we know we "want" color) case "$TERM" in xterm-color) color_prompt=yes;; esac # uncomment for a colored prompt, if the terminal has the capability; turned # off by default to not distract the user: the focus in a terminal window # should be on the output of commands, not on the prompt #force_color_prompt=yes if [ -n "$force_color_prompt" ]; then if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then # We have color support; assume it's compliant with Ecma-48 # (ISO/IEC-6429). (Lack of such support is extremely rare, and such # a case would tend to support setf rather than setaf.) color_prompt=yes else color_prompt= fi fi if [ "$color_prompt" = yes ]; then PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ ' else PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ ' fi unset color_prompt force_color_prompt # If this is an xterm set the title to user@host:dir case "$TERM" in xterm*|rxvt*) PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1" ;; *) ;; esac # enable color support of ls and also add handy aliases if [ -x /usr/bin/dircolors ]; then test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)" alias ls='ls --color=auto' #alias dir='dir --color=auto' #alias vdir='vdir --color=auto' alias grep='grep --color=auto' alias fgrep='fgrep --color=auto' alias egrep='egrep --color=auto' fi # some more ls aliases alias ll='ls -alF' alias la='ls -A' alias l='ls -CF' # Add an "alert" alias for long running commands. Use like so: # sleep 10; alert alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"' # Alias definitions. # You may want to put all your additions into a separate file like # ~/.bash_aliases, instead of adding them here directly. # See /usr/share/doc/bash-doc/examples in the bash-doc package. if [ -f ~/.bash_aliases ]; then . ~/.bash_aliases fi # enable programmable completion features (you don't need to enable # this, if it's already enabled in /etc/bash.bashrc and /etc/profile # sources /etc/bash.bashrc). if ! shopt -oq posix; then if [ -f /usr/share/bash-completion/bash_completion ]; then . /usr/share/bash-completion/bash_completion elif [ -f /etc/bash_completion ]; then . /etc/bash_completion fi fi 

我的.profile文件是:

 # ~/.profile: executed by the command interpreter for login shells. # This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login # exists. # see /usr/share/doc/bash/examples/startup-files for examples. # the files are located in the bash-doc package. # the default umask is set in /etc/profile; for setting the umask # for ssh logins, install and configure the libpam-umask package. #umask 022 # if running bash if [ -n "$BASH_VERSION" ]; then # include .bashrc if it exists if [ -f "$HOME/.bashrc" ]; then . "$HOME/.bashrc" fi fi # set PATH so it includes user's private bin if it exists if [ -d "$HOME/bin" ] ; then PATH="$HOME/bin:$PATH" fi 

文件/etc/profile在这里: http : //paste.ubuntu.com/5781361/

解决方法

首先,我认为当你进入tty1时你会参考 – Ctrl + Alt + F1

现在,我认为发生了你最有可能发生的事情,因为你在~/.bashrc~/.profile文件或包含各种初始化的其他文件中有一个奇怪的字符,如♦( 钻石套装字符askubuntu版主的特殊徽章 )命令。

正如您在下一张图片中看到的那样,我编辑了~/.bashrc文件,将♦字符放在一行中。 因此,当我打开终端时,它会出现您所描述的问题:

终奌站

当我使用Ctrl + Alt + F1进入tty1时,情况也是如此。

调用shell时包含初始化命令的文件: /etc/profile/etc/bashrc~/.bash_login~/.profile~/.bashrc~/.bash_aliases以及其他可能的文件。 请参阅Shell初始化文件 。

要快速检查其中一个文件是否有错误,可以使用source命令。 例如:

 source ~/.bashrc 

来源简介

最终解决方案

在检查了http://paste.ubuntu.com/5781361/上的/etc/profile后,我发现第31行有“从右到左覆盖” – unicode字符。 只需用sudo -H gedit /etc/profile打开/etc/profile文件,确保删除这个奇怪的字符,问题就会消失。

档案文件

作为娱乐,例如,在HTML中,如果您在行前面使用十进制代码( )插入此unicode字符,请查看发生的情况:

这段文字是阿拉伯语 – 英语!

另一个更通用的解决方案

我们将使用“ 陷阱 ”找到导致错误的确切命令。

首先,我们必须在~/bin目录中创建一个新的脚本文件,我们称之为lib.trap.shgedit ~/bin/lib.trap.sh ),内部如下:

 lib_name='trap' lib_version=20130620 #changed from lib_version=20121026 found it at https://stackoverflow.com/a/13099228/2353900 to work well at initialization of the shell stderr_log="/dev/shm/stderr.log" # # TO BE SOURCED ONLY ONCE: # ###~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## if test "${g_libs[$lib_name]+_}"; then return 0 else if test ${#g_libs[@]} == 0; then declare -A g_libs fi g_libs[$lib_name]=$lib_version fi # # MAIN CODE: # ###~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## set -o pipefail # trace ERR through pipes set -o errtrace # trace ERR through 'time command' and other functions set -o nounset ## set -u : exit the script if you try to use an uninitialised variable set -o errexit ## set -e : exit the script if any statement returns a non-true return value exec 2>"$stderr_log" ###~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## # # FUNCTION: EXIT_HANDLER # ###~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## function exit_handler () { local error_code="$?" test $error_code == 0 && return; # # LOCAL VARIABLES: # ------------------------------------------------------------------ # local i=0 local regex='' local mem='' local error_file='' local error_lineno='' local error_message='unknown' local lineno='' # # PRINT THE HEADER: # ------------------------------------------------------------------ # # Color the output if it's an interactive terminal test -t 1 && tput bold; tput setf 4 ## red bold echo -e "\n(!) EXIT HANDLER\n" # # GETTING LAST ERROR OCCURRED: # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # # # Read last file from the error log # ------------------------------------------------------------------ # if test -f "$stderr_log" then stderr=$( tail -n 1 "$stderr_log" ) rm "$stderr_log" fi # # Managing the line to extract information: # ------------------------------------------------------------------ # if test -n "$stderr" then # Exploding stderr on : mem="$IFS" local shrunk_stderr=$( echo "$stderr" | sed 's/\: /\:/g' ) IFS=':' local stderr_parts=( $shrunk_stderr ) IFS="$mem" # Storing information on the error error_file="${stderr_parts[0]}" error_lineno="${stderr_parts[1]}" error_message="" for (( i = 3; i <= ${#stderr_parts[@]}; i++ )) do error_message="$error_message "${stderr_parts[$i-1]}": " done # Removing last ':' (colon character) error_message="${error_message%:*}" # Trim error_message="$( echo "$error_message" | sed -e 's/^[ \t]*//' | sed -e 's/[ \t]*$//' )" fi # # GETTING BACKTRACE: # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # _backtrace=$( backtrace 2 ) # # MANAGING THE OUTPUT: # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # local lineno="" regex='^([az]{1,}) ([0-9]{1,})$' if [[ $error_lineno =~ $regex ]] # The error line was found on the log # (eg type 'ff' without quotes wherever) # -------------------------------------------------------------- then local row="${BASH_REMATCH[1]}" lineno="${BASH_REMATCH[2]}" echo -e "FILE:\t\t${error_file}" echo -e "${row^^}:\t\t${lineno}\n" echo -e "ERROR CODE:\t${error_code}" test -t 1 && tput setf 6 ## white yellow echo -e "ERROR MESSAGE:\n$error_message" else regex="^${error_file}\$|^${error_file}\s+|\s+${error_file}\s+|\s+${error_file}\$" if [[ "$_backtrace" =~ $regex ]] # The file was found on the log but not the error line # (could not reproduce this case so far) # ------------------------------------------------------ then echo -e "FILE:\t\t$error_file" echo -e "ROW:\t\tunknown\n" echo -e "ERROR CODE:\t${error_code}" test -t 1 && tput setf 6 ## white yellow echo -e "ERROR MESSAGE:\n${stderr}" # Neither the error line nor the error file was found on the log # (eg type 'cp ffd fdf' without quotes wherever) # ------------------------------------------------------ else # # The error file is the first on backtrace list: # Exploding backtrace on newlines mem=$IFS IFS=' ' # # Substring: I keep only the carriage return # (others needed only for tabbing purpose) IFS=${IFS:0:1} local lines=( $_backtrace ) IFS=$mem error_file="" if test -n "${lines[1]}" then array=( ${lines[1]} ) for (( i=2; i<${#array[@]}; i++ )) do error_file="$error_file ${array[$i]}" done # Trim error_file="$( echo "$error_file" | sed -e 's/^[ \t]*//' | sed -e 's/[ \t]*$//' )" fi echo -e "ROW, FILE:\t\t${lines[2] }\n" echo -e "ERROR CODE:\t${error_code}" test -t 1 && tput setf 6 ## white yellow if test -n "${stderr}" then echo -e "ERROR MESSAGE:\n${stderr}" else echo -e "ERROR MESSAGE:\n${error_message}" fi fi fi # # PRINTING THE BACKTRACE: # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # test -t 1 && tput setf 7 ## white bold echo -e "\n$_backtrace\n" # # EXITING: # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # test -t 1 && tput setf 4 ## red bold echo "Exiting!" test -t 1 && tput sgr0 # Reset terminal exit "$error_code" } trap exit_handler ERR # ! ! ! TRAP EXIT ! ! ! #trap exit ERR # ! ! ! TRAP ERR ! ! ! ###~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## # # FUNCTION: BACKTRACE # ###~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## function backtrace { local _start_from_=0 local params=( "$@" ) if (( "${#params[@]}" >= "1" )) then _start_from_="$1" fi local i=0 local first=false while caller $i > /dev/null do if test -n "$_start_from_" && (( "$i" + 1 >= "$_start_from_" )) then if test "$first" == false then echo "BACKTRACE IS:" first=true fi caller $i fi let "i=i+1" done } return 0 

现在,你唯一需要做的就是在文件/etc/profilesudo -H gedit /etc/profile )的开头放下一行:

 source '/home//bin/lib.trap.sh' 

使用您的用户名更改 。 像这样,调用shell时包含初始化命令的所有文件都将通过“陷阱”。

例如,要测试/etc/profile是否存在错误命令,请运行terminal next命令:

bash源/ etc / profile

如果出现问题,例如在这种情况下,结果将是:

陷阱

所以,现在我们确定在第32行的/etc/profile文件中存在一个问题( command not found )(它不在上面的第31行,因为我们在文件的开头插入了一个新行) 。

非常感谢Luca Borrione从这个答案中获得的脚本,帮助我完成了这个通用的解决方案。

要调试bash的初始化脚本,请运行以下命令(在虚拟控制台登录后)。

 PS4='+ $BASH_SOURCE:$LINENO:' bash -xlic '' 

以上以交互式( -i )登录( -l )模式运行bash,与登录虚拟控制台时login程序相同。 -c ''在运行初始化脚本后立即退出, -xPS4=...使它在运行它们之前输出每个命令,以及该命令的文件名和行号。 这应该有助于确定无效命令所在的文件的哪一行。

在旁注中,♦是虚拟控制台用于打印没有符号的字符的默认字体的符号。

在搜索初始化文件时,查找用于输出♦的hex可能会有所帮助。 根据Unicode Character’BLACK DIAMOND SUIT’ ,♦的hex代码是2666。 注意:至少有一个其他hex代码25C6,它产生相同或相似的符号。 查看“钻石”的搜索结果。 Unicode字符搜索

也许像\u2666这样的东西就在其中一个脚本中。 来自Bash参考手册的echo – “\ uhhhh Unicode(ISO / IEC 10646)字符,其值为hex值HHHH(一到四个hex数字)”

这取决于所使用的字符编码,因此您可能希望首先搜索最可能的字符编码。 echo $LC_CTYPE应该返回shell使用的字符编码。 请参见如何获取终端的字符编码

写出可以编辑bashrc文件的已知工具的完整路径,以及bashrc文件的完整路径。

 /bin/nano /home/username/.bashrc 

查找PATH变量的任何滥用行为并将其注释掉。 可能在尝试向您的路径添加内容时,它是单引号而不是双引号。

 PATH='$PATH:/path/to/new/tool' # very BAD, single quotes won't expand PATH # ^ ^ PATH="$PATH:/path/to/new/tool" # Good! The double quotes allow variable expansion 

将.bashrc复制到https://www.shellcheck.net/这样的工具中,看看你是否对使用bash有任何明显的问题。

希望有所帮助。