Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> การเขียนโปรแกรม Bash

เชี่ยวชาญ Bash: คู่มืออัลติเมตสำหรับ Sysadmin

ทุกอาชีพมีเครื่องมือที่มืออาชีพใช้บ่อยที่สุด สำหรับ Sysadmin หลายคน เครื่องมือนั้นคือ Shell ของพวกเขา บน Linux และ Unix-like ส่วนใหญ่ Shell เริ่มต้นคือ Bash

Bash เป็นโปรแกรมที่เก่า למדי - เริ่มต้นในปลายทศวรรษ 1980 - แต่สร้างขึ้นบน Shell ที่เก่ากว่ามาก เช่น C Shell (csh) ซึ่งเก่ากว่าประมาณ 10 ปี เนื่องจากแนวคิดของ Shell เก่าแก่ขนาดนี้ จึงมีความรู้ลับโบราณจำนวนมากรอให้กลืนกิน เพื่อให้ชีวิตของ Sysadmin ทุกคนง่ายขึ้น

มาดูพื้นฐานบางส่วนกัน

ใครเคยรันคำสั่งเป็น Root โดยไม่ได้ตั้งใจ และทำให้เกิดปัญหา? ยกมือ

ฉันค่อนข้างแน่ใจว่าหลายคนเคยเป็น "คนนั้น" ไปแล้ว มากจริง นี่คือเทคนิคง่ายๆ เพื่อไม่ให้คุณกระดอนหินก้อนเดิมอีกครั้ง

ใช้ Aliases

แรก ตั้ง Aliases สำหรับคำสั่งอย่าง mv และ rm ชี้ไปที่ mv -i และ rm -i จะทำให้รัน rm -f /boot ขอยืนยันอย่างน้อย ใน RHEL Aliases เหล่านี้ตั้งค่าไว้โดยค่าเริ่มต้นสำหรับบัญชี Root

หากต้องการตั้ง Aliases เหล่านี้สำหรับบัญชีผู้ใช้ทั่วไป ให้เพิ่มสองบรรทัดนี้ลงในไฟล์ .bashrc ในโฮมไดเรกทอรี (ทำงานกับ sudo ได้):

alias mv='mv -i'
alias rm='rm -i'

ทำให้ Root Prompt โดดเด่น

อีกวิธีป้องกันอุบัติเหตุคือทำให้รู้ว่ากำลังใช้บัญชี Root โดยทำให้ Root Prompt โดดเด่นจาก Prompt ปกติ

หากใส่โค้ดต่อไปนี้ใน .bashrc ของ Root โฮมไดเรกทอรี จะได้ Root Prompt สีแดงพื้นดำ ทำให้ชัดเจนว่าควรระวัง:

export PS1="\[$(tput bold)$(tput setab 0)$(tput setaf 1)\]\u@\h:\w # \[$(tput sgr0)\]"

ควรหลีกเลี่ยงล็อกอินเป็น Root ให้มากที่สุด และใช้ sudo แทน แต่นั่นเป็นเรื่องอื่น

หลังจากใช้เทคนิคเล็กๆ ป้องกัน "ผลข้างเคียงจากการใช้ Root โดยไม่ได้ตั้งใจ" มาดูสิ่งดีๆ ที่ Bash ช่วยได้ในงานประจำวัน

ควบคุม History

คุณน่าจะรู้ว่า กดปุ่มลูกศรขึ้นใน Bash จะเห็นและนำคำสั่งเก่าไปใช้ใหม่ได้ เพราะถูกบันทึกใน .bash_history ไฟล์นี้มีการตั้งค่าและคำสั่งที่มีประโยชน์มาก

ก่อนอื่น ดู History ทั้งหมดด้วย history หรือจำกัด 30 คำสั่งล่าสุดด้วย history 30 แต่นั่นเป็นแค่พื้นฐาน คุณควบคุมได้มากกว่านี้ว่าจะบันทึกอะไรและอย่างไร

เช่น เพิ่มใน .bashrc คำสั่งที่ขึ้นต้นด้วย Space จะไม่ถูกบันทึก:

HISTCONTROL=ignorespace

มีประโยชน์หากต้องส่งรหัสผ่านแบบ Plaintext (แย่แต่ยังเกิดขึ้น)

หากไม่ต้องการคำสั่งที่รันบ่อยปรากฏใน History ใช้:

HISTCONTROL=ignorespace:erasedups

ทุกครั้งที่ใช้คำสั่ง ทุกครั้งที่ผ่านมาจะถูกลบออก เหลือแค่ครั้งล่าสุด

การตั้งค่า History ที่ชอบคือ HISTTIMEFORMAT จะเติม Timestamp หน้าทุก Entry เช่น ใช้:

HISTTIMEFORMAT="%F %T "

พิมพ์ history 5 จะได้ข้อมูลครบ:

1009 2018-06-11 22:34:38 cat /etc/hosts
1010 2018-06-11 22:34:40 echo $foo
1011 2018-06-11 22:34:42 echo $bar
1012 2018-06-11 22:34:44 ssh myhost
1013 2018-06-11 22:34:55 vim .bashrc

ทำให้หาคำสั่งที่ใช้เมื่อ 2 วันก่อน (เช่น ตั้ง SSH Tunnel) ง่ายขึ้นมาก

Best Practices สำหรับ Bash

สรุปด้วย Top 11 แนวทางปฏิบัติที่ดี (หรือพอใช้) เมื่อเขียน Bash Script

  1. Bash Script อาจซับซ้อน คอมเมนต์ราคาถูก หากสงสัยว่าควรเพิ่มคอมเมนต์ ให้เพิ่ม ไปพักสุดสัปดาห์กลับมาต้องเสียเวลาจดจำว่าทำอะไรวันศุกร์ แสดงว่าลืมคอมเมนต์

  1. ห่อชื่อตัวแปรด้วย Curly Braces เช่น ${myvariable} ทำเป็นนิสัย ทำให้ ${variable}_suffix เป็นไปได้ และเพิ่มความสอดคล้อง
  1. อย่าใช้ Backticks เมื่อ Evaluate นิพจน์ ใช้ $() แทน เช่น:
    for file in $(ls); do

    ไม่ใช่

    for file in `ls`; do

    ตัวเลือกแรก Nest ได้ อ่านง่าย และทำให้ Sysadmin ส่วนใหญ่พอใจ อย่าใช้ Backticks

  1. ความสอดคล้องดี เลือกสไตล์หนึ่ง ทำต่อเนื่องตลอดสคริปต์ ชอบให้ใช้ $() ห่อตัวแปรด้วย Curly Braces ใช้ Space 2 หรือ 4 ตัว Indent ไม่ใช่ Tab แต่แม้เลือกผิด ก็ทำผิดอย่างสม่ำเสมอ
  1. ใช้ Shebang ให้ถูกต้อง สำหรับ Bash Script ที่รันด้วย Bash เท่านั้น มักใช้ #!/usr/bin/bash อย่าใช้ #!/bin/sh หรือ #!/usr/bin/sh จะรันได้แต่เป็น Compatibility Mode อาจมี Side Effect (เว้นแต่ต้องการ Compatibility Mode)
  1. เปรียบเทียบ String ควร Quote ตัวแปรใน If-Statement เพราะถ้าตัวแปรว่าง Bash จะ Error บรรทัดแบบ:
    if [ ${myvar} == "foo" ]; then
    echo "bar"
    fi

    และ Evaluate เป็น False บรรทัดแบบ:

    if [ "${myvar}" == "foo" ]; then
    echo "bar"
    fi

    นอกจากนี้ หากไม่แน่ใจเนื้อหาตัวแปร (เช่น Parse User Input) ให้ Quote เพื่อป้องกันการตีความ Special Characters และให้ตัวแปรถูกมองว่าเป็นคำเดียวแม้มี Whitespace

  1. เรื่องความชอบ แต่อยากใช้ Double Equals (==) แม้เปรียบเทียบ String ใน Bash ก็ได้ เพราะความสอดคล้อง แม้ Single Equals จะทำงานได้สำหรับ String แต่สมองคิดว่า "Single Equals คือ Assignment Operator!"
  1. ใช้ Exit Code ให้เหมาะสม หาก Script ล้มเหลว ให้แสดงข้อความ Error (ดีกว่ามีวิธีแก้) และส่ง Exit Code ไม่เป็นศูนย์:
    # we have failed
    echo "Process has failed to complete, you need to manually restart the whatchamacallit"
    exit 1

    ทำให้เรียก Script จาก Script อื่นและตรวจสอบความสำเร็จได้ง่าย

  1. ใช้กลไก Built-in ของ Bash ให้ค่า Default ที่เหมาะสม หรือโยน Error หากตัวแปรที่คาดหวังไม่ได้ถูก Define:
    # this sets the value of $myvar to redhat, and prints 'redhat'
    echo ${myvar:=redhat}
    # this throws an error reading 'The variable myvar is undefined, dear reader' if $myvar is undefined
    ${myvar:?The variable myvar is undefined, dear reader}
  1. โดยเฉพาะ Script ใหญ่ หรือทำงานร่วมกับคนอื่น พิจารณาใช้ local เมื่อ Define ตัวแปรใน Function local สร้างตัวแปร Local มองเห็นได้เฉพาะใน Function นั้น ลดโอกาสชนตัวแปร
  1. ทุก Sysadmin ต้อง Debug บน Console บ้าง ไม่ว่าจะ Console จริงใน Data Center หรือ Virtual ผ่าน Platform หากต้อง Debug Script แบบนั้น คุณจะขอบคุณตัวเองที่จำไว้: อย่าทำบรรทัดใน Script ยาวเกินไป!



    บนระบบหลายตัว ความกว้าง Console เริ่มต้นยังคงเป็น 80 ตัวอักษร หาก Debug Script บน Console และ Script มีบรรทัดยาวมาก คุณจะเป็น "Panda เสียใจ" นอกจากนี้ Script ที่บรรทัดสั้นกว่า (Default 80 chars) อ่านง่าย เข้าใจง่ายใน Editor ปกติด้วย!

ฉันชอบ Bash อย่างแท้จริง สามารถใช้ชั่วโมงเขียนหรือแลกเปลี่ยนเทคนิคกับเพื่อนร่วมงาน อย่าลืมวางเทคนิคโปรดใน Comments นะครับ!