ฉันจะกำหนดสีของข้อความแสดงข้อผิดพลาดใน Bash ได้อย่างไร


7

เป็นไปได้หรือไม่ที่จะปรับแต่งแอตทริบิวต์ข้อความแสดงข้อผิดพลาดของ Bash

ตัวอย่างเช่นเป็นไปได้ที่จะแก้ไข .bash_profile เพื่อรับข้อความแสดงข้อผิดพลาด Bash ต่อไปนี้

-bash: cd: foo: No such file or directory

ในสีแดง?

คำตอบ:


2

น่าเศร้าที่ไม่มี PS ตัวแปรพรอมต์เพื่อควบคุมวิธีการนำเสนอข้อผิดพลาด bash

stderred เป็นโซลูชั่นที่ครอบคลุมสำหรับปัญหาประเภทนี้ แต่มัน จะไม่ทำงานหากไม่มีการแก้ไขเนื่องจากมีการยกเว้นฮาร์ดโค้ด สำหรับ bash (อ่านต่อเพื่อเหตุผลที่ดีว่าทำไม) นอกจากนี้ยังค่อนข้างรบกวน (การฉีด DLL)

hilite คุณต้องใช้มันเป็น wrapper ซึ่งจะไม่สามารถใช้ได้กับคำสั่ง bash builtin cd.

คำถามของคุณถามเฉพาะเกี่ยวกับข้อความผิดพลาดทุบตีเหล่านี้จะถูกส่งไป stderrแต่ stderr ยังแชร์กับกระบวนการลูกใด ๆ เช่นคำสั่งอื่น ๆ ฉันไม่แน่ใจว่าคุณต้องการแยกแยะทั้งสองหรือไม่

ปัญหาที่ซ่อนอยู่ที่นี่ก็คือ bash ตัวเองเขียนพรอมต์และอินพุตของคุณ (echo) ไปที่ stderr. เพื่อพิสูจน์:

bash              # start a sacrificial shell
exec 2> tmpfile   # change stderr to a file
ls                # you will see no prompt, and no command echo
... 
exit              # quit sacrificial shell
cat tmpfile       # contains PS1 prompt, your commands (and any errors too)

Builtins call (หรืออย่างน้อยควรจะเรียก) builtin_error() ฟังก์ชั่นภายในเพื่อพิมพ์ข้อผิดพลาดนี้เรียกโดยไม่มีเงื่อนไข fprintf() ไปยัง stderrดังนั้นตัวเลือกมีน้อย

โดยไม่ต้องกระโดดผ่านห่วงหรือปะ bashวิธีง่ายๆในการเน้นข้อผิดพลาดคือ:

function _t_debug() 
{
    if [ "${BASH_COMMAND:0:6}" != "_t_err" ]; then
        _lastcmd="$BASH_COMMAND"
    fi  
}
function _t_err() 
{
    local rc=$1 nn _type _argv
    #shift; pipe=($*)
    #if [ ${#pipe[*]} -gt 1 ]; then
    #    for ((nn=1; nn<=${#pipe[*]};nn++));do
    #        rc=${pipe[$((nn-1))]}
    #        echo -n "[$nn]=$rc ";
    #        ((rc >=128)) && echo -n "($((rc-128))) "
    #    done
    #fi

    read -a _argv <<< ${_lastcmd}
    _type=$(type -t "${_argv[0]}")

    if [ -n "$_lastcmd" ]; then
        tput setf 4
        printf 'Error %s: "%s"' "${_type}" "${_lastcmd:-unknown command}"
        tput sgr 0
        printf "\n"
    fi

    ((rc >=128)) && echo "[rc=$rc ($((rc-128)))]" ||
    echo "[rc=$rc]"
}
trap '_t_err $? ${PIPESTATUS[*]}' ERR
trap '_t_debug' DEBUG

สิ่งนี้ใช้ทุบตี DEBUG เพื่อดักแคชแต่ละบรรทัดคำสั่งก่อนการดำเนินการและ ERR ดักเพื่อส่งออกโค้ดส่งคืนหากไม่ใช่ศูนย์ นี้จะไม่แม้ว่าสำหรับทุบตีบางอย่างในตัว (เฉพาะ คำสั่งผสม : while/case/for/if และอื่น ๆ ดูหน้าคน)

ฉันใช้รูปแบบนี้ในของฉัน .profileแม้ว่าฉันจะใช้ pipe[]/PIPESTATUS[] บิตแสดงความคิดเห็นข้างต้นมันเข้ากันไม่ได้กับดัก DEBUG ตามที่ปรากฏด้านบน หากคุณแสดงความคิดเห็นออก trap DEBUG จากนั้นคุณสามารถใช้มันเพื่อแสดงโค้ดส่งคืนของแต่ละคำสั่งในไปป์ไลน์

(เนื่องจากมีการอ้างอิงถึง command_not_found เบ็ดฟังก์ชั่นคือ bash-4.0 +.)


2

คุณอาจต้องการตรวจสอบ stderrred สำหรับวิธีการแก้ปัญหาที่ถาวรมากขึ้น


1

วิธีการแก้ปัญหาด้านล่างใช้ได้กับสิ่งที่คุณต้องการ:

# whatever_command 2> >(while read line; do echo -e "\e[01;31m$line\e[0m" >&2; done)

โดยทั่วไปคำสั่งด้านบนจะพิมพ์ออกมา stderr ในสีแดง.

ตรวจสอบภาพหน้าจอด้านล่าง:

enter image description here

ฉันไม่ทราบวิธีการทำให้ถาวรนี้ อย่างไรก็ตามสิ่งนี้ควรให้คำแนะนำแก่คุณอย่างแน่นอน


0

บางทีคุณสามารถลอง hilite - ฉันคิดว่านี่เป็นหนึ่งในวิธีแก้ปัญหาที่ง่ายที่สุด


0

ใส่สิ่งนี้ลงในของคุณ ~/.bashrc หรือ ~/.bash_profile ไฟล์สำหรับการแก้ไขถาวรหรือหากคุณต้องการให้เป็นการชั่วคราวเพียงพิมพ์สิ่งนี้ลงใน bash.

command_not_found_handle () { 
  tput bold;
  tput setaf 1;
  echo "$0: $1: command not found"; 
  tput sgr0; 
}

มันจะทำให้ bash เอาต์พุตคำสั่งไม่พบข้อผิดพลาดเป็นตัวหนาและสีแดง ไปข้างหน้าและออกไป tput bold; เพื่อให้ข้อความแสดงข้อผิดพลาดไม่เป็นตัวหนาหรือเปลี่ยน tput setaf 1 ไปยังหมายเลขอื่นสำหรับสีอื่น หวังว่ามันจะช่วย !!

แก้ไข

นี่เป็นเวอร์ชั่นใหม่และปรับปรุงด้านบน

command_not_found_handle () {
  echo -e "\e[1;31m$0: $1: command not found\e[0;0m";
  return 127; #return bash's error code for command not found
}

แก้ไข 2

If the name is neither a shell function nor a builtin, and contains no slashes, bash
searches each element of the PATH for a directory containing an executable file by that
name. Bash uses a hash table to remember the full pathnames of executable files (see hash
under SHELL BUILTIN COMMANDS below). A full search of the directories in PATH is performed
only if the command is not found in the hash table. If the search is unsuccessful, the
shell searches for a defined shell function named command_not_found_handle. If that
function exists, it is invoked with the original command and the original command's
arguments as its arguments, and the function's exit status becomes the exit status of the
shell. If that function is not defined, the shell prints an error message and returns an
exit status of 127.

เอามาจาก manpage ของทุบตี

ดังนั้นหากวิธีนี้ใช้ไม่ได้ผลอาจเป็นเพราะเปลือกของคุณไม่จริง bashหรือเป็นรุ่นที่ได้รับการแก้ไขของ bash.


ขอบคุณ BenjiWiebe โซลูชันของคุณดูน่าสนใจมาก แต่น่าเสียดายที่วิธีนี้ใช้งานไม่ได้ command_not_found_handle () { echo "Error..." }: ฉันยังได้รับพื้นฐาน -bash: foo: command not found? ฉันใช้ระบบปฏิบัติการ Mac OSX
htaidirt

@Hassinus คุณใช้จริงๆ bash? ดูการแก้ไข 2
BenjiWiebe

1
@BenjiWiebe: โซลูชันของคุณจะดักจับข้อผิดพลาดเฉพาะข้อเดียวเท่านั้นความล้มเหลวในการค้นหาคำสั่ง ตัวอย่างในคำถามไม่ใช่ข้อผิดพลาดดังกล่าว
chepner
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.