Bash Script – La liếm với bộ 3 Variable, Argument & User Input

Như đã hứa hẹn cuối phần Giải ngố Kali Linux – Phần 4: Ép xung tốc độ thao tác Command Line với Bash và nhập môn Bash Script, kỳ này tôi sẽ dành thời gian để bàn thêm một số vấn đề hay ho với Bash Script. Cụ thể các đối tượng được tôi nhấn mạnh trong kỳ này là Variable (biến), Argument (tham số) và User Input (thông tin người dùng nhập liệu).

#1 Nhắc lại chuyện cũ

Trước khi bắt đầu, để tôi nhắc lại một số ý quan trọng để bạn dễ theo dõi:

  • Bash script hiểu đơn giản là script chạy với Command Interpreter bash, thường ở dạng kết hợp nhiều command và gom vô một file *.sh (cái này là optional extension – tùy chọn mở rộng để dễ nhận diện) nhằm thực hiện tác vụ theo một kịch bản nhất định.
  • Dòng đầu tiên của Bash script bạn sẽ hay thấy kiểu như “#! bin/bash”. Trong đó “#! (đọc là Shebang) có vai trò như dấu hiệu để thông báo cho hệ điều hành ý kiến chỉ đạo: “Ê ku! Xử lý cái script này bằng Interpreter bin/bash cho anh” (mặc định script sẽ được xử lý với sh);

Bạn cũng cần nhớ file Bash script phải được cấp quyền thực thi để có thể sử dụng. Việc cấp quyền có thể thực hiện nhanh gọn với command:

chmod +x bash_script_filename

Sau đó bạn có thể chạy thử với command:

./ bash_script_filename

Lưu ý: “./” là path notation là ký hiệu đường dẫn tương ứng cho thư mục hiện hành. Do vậy cái Bash script bạn đang muốn chạy phải nằm ở đây thì cái command trên mới có tác dụng.

#2 Các chiêu trò với Variable – Biến

#2.1 Variable declare & reference – Vấn đề khai báo và tham chiếu biến

Để có thể reference (tham chiếu) đến một biến đã declare (khai báo) thì bạn cần đặt ký tự “$” trước variable name.

Ví dụ, bạn khai báo một biến như sau:

test=testing (biến test có giá trị là testing)

Thì sau đó bạn có tham chiếu đến nó theo kiểu:

echo $test

Variable declare & reference

Lưu ý:

  • Echo là cách để minh họa việc tham chiếu cho nhanh thôi, bạn có thể dùng cách khác nếu thích;
  • Bash là dạng case-sensitive (nghĩa là có phân biệt chữ hoa và chữ thường) nên để chơi “lâu dài” với nó, bạn cần chốt luôn phương thức đặt tên biến để khi cần phát triển/ bảo trì cái script thì vẫn nội dung vẫn đồng nhất chứ không rối nùi (hiển nhiên, việc đặt tên biến cũng nên thể hiện rõ ý đồ chiến thuật chứ không phải kiểu “test” vớ vẩn như tôi làm ở trên).

#2.2 Xử lý các ký tự đặc biệt

Ngoài ra, bạn cũng cần lưu ý các ký tự đặc biệt space (khoảng trắng) khi chơi với Bash. Quay lại ví dụ trên, nếu ở trên bạn khai báo với giá kiểu “test1=just testing” sẽ bị lỗi “command not found”.

Lúc này bạn cần chuyển sang dùng singe quotes (‘’) hoặc double quotes (“”) để bao cái text value (just testing) ở trên lại. Tuy nhiên, 2 con hàng này cũng tiềm ẩn vấn đề cần lưu ý như sau:

  • singe quotes: toàn bộ đám thông tin bên trong nó đều được xem là ký tự đơn thuần;
  • double quotes: toàn bộ đám thông tin bên trong nó đều được xem là ký tự đơn thuần ngoại trừ 3 mặt nồi “$”, “`” và “\”.

Tôi minh họa cho rõ cái chỗ rối rắm này qua ví dụ sau:

test1='just testing'

echo $test1

test2="again $test1"

echo $test2

Variable special chars
Variable special chars

Lúc này bạn sẽ thấy, ký tự space trong ví dụ của biến test1 với singe quotes vẫn được giữ nguyên là  chính nó. Nhưng trong double quotes với biến test2, space sẽ trở thành command delimiter (kí tự để phân tác lệnh). Cụ thể, $test1 trong giá trị gán “again $test1” sẽ tương ứng việc tham chiếu đến biến test1 chứ không đơn thuần là text “$test1” nữa (Móa! Sao tôi có cảm giác giải thích xong nó còn rối hơn hay sau ấy!)

Dù có thể đáp ứng được một phần nhu cầu công việc, nhưng việc khai báo “cứng” giá trị của biến như trên không được linh hoạt lắm (với script nội dung dài thì thay đổi thông tin thì bạn phải soi lồi con mắt ra để cập nhật tương ứng). Thực tế bạn sẽ hay gặp tình huống biến có giá trị lấy từ output của một command/ program nào đó. Khi đó với việc thiết lập giá trị của biến theo dạng này, bạn có được một thứ gọi là command substitution thông qua việc sử dụng cú pháp:

variable_name=$(command)

Cụ thể với ví dụ:

user=$(whoami)

echo $user

Variable command substitution
Variable command substitution

Lưu ý: Nếu không thích parentheses “()”, bạn có thể dùng backtick charater “`”. Khi đó ví dụ trên sẽ tương ứng là user=$`whoami`. Tuy nhiên, tôi nghe giang hồ nói về bản chất việc sử dụng parentheses backtick charater là không giống nhau, dù kết quả trong phần lớn tình huống là tương đồng.

#3 Làm quen với Argument – Tham số

Thực ra việc sử dụng tham số có thể bạn đã thấy nhiều lần rồi. Trường hợp đơn giản bạn có thể thấy là khi chạy command:

ls -l /usr/bin

Trong command trên, “-l” và “/usr/bin” là argument của command ls. Quay lại vấn đề chính, với Bash script bạn có thể sử dụng argument đơn giản với ví dụ test_arg.sh có nội dung minh họa như sau:

#!/bin/bash

echo "first argument is $1 and second argument is $2"

Argument test script
Argument test script

Lưu ý: Nếu chưa biết cách xử lý file với text editor thì bạn tham khảo nội dung Giải ngố Kali Linux – Phần 6: Bộ 3 nguyên tử text editor nano/vi/vim và cách buff damage với skill so sánh nội dung file bằng comm/diff. Ở trên tôi dùng với nano.

Sau khi cấp quyền thực thi cho file với command:

sudo chmod +x ./test_arg.sh

Bạn có thể chạy thử với các argument với command:

./test_arg.sh one two

Argument test script result
Argument test script result

Giờ thì bạn đã biết $1$2 tương ứng với argument thứ 1 và thứ 2 của Bash script. Ngoài 2 thằng này, bạn còn có thể gặp thêm một số nhân vật khác trong dòng họ nhà nó như bảng sau.

Tên biến Mô tả
$0 Tên của Bash script
$1 – $9 9 argument đầu của Bash script
$# Số argument đút vô Bash script
$@ Tất cả argument đút vô Bash script
$? Exit status của process chạy gần nhất
$$ Process ID của script hiện hành
$USER Username của user đang chạy script
$HOSTNAME Hostname của máy
$RANDOM Một số ngẫu nhiên
$LINENO Dòng hiện hành trong script

#4 Làm màu với User input – Thông tin người dùng nhập liệu

Với kiểu argument nói trên, bạn đã tăng thêm độ linh hoạt cho Bash script. Tuy nhiên, đời thường không như mơ. Đôi khi script của bạn sẽ cần tương tác và lấy thông tin từ người dùng để xử lý nên argument cũng không đáp ứng được. Khi đó, bạn có thể chuyển sang dạng interative user input (nhập liệu có tương tác với người dùng). Với phương án này, bạn sẽ cần đến read command trong Bash script để bắt user input và gán vô biến. Ví dụ đơn giản với file input.sh có nội dung như sau:

#!/bin/bash

echo "You want a piece of me, boy: Y/N?"

read answer

echo "Your answer was $answer"

User input test script
User input test script

Sau đó bạn cấp quyền thực thi với command:

chmod +x ./input.sh (Tôi bắt đầu thấy ngán việc lập lại nội dung này rồi nên từ đoạn này về sau bạn tự nhớ nhé. Bạn lỡ quên cũng không sau, nó sẽ chửi thẳng mặt bạn khi run script mà chưa cấp quyền thực thi thôi)

Sau đó chạy thử với ./input.sh bạn sẽ thấy:

User input test script result
User input test script result

Việc sử dụng với read command như trên là dạng đơn sơ mộc mạc nhất, bạn có thể tăng mức độ “làm màu” với các tùy chọn bổ sung phổ biến như:

  • -p: chỉ định prompt (dấu nhắc) để người dùng nhập liệu;
  • -s: bật chế độ user input silent (tức là không thấy hiển thị đang nhập cái gì)

Tôi ví dụ minh họa như sau với file another_input.sh có nội dung như sau:

#!/bin/bash

# Prompt the user for credentials

read -p 'Username: ' username

read -sp 'Password: ' password

echo "Hi noob, your username is: " $username " and your password is" $password

User input test script option
User input test script option

Sau đó chạy thử với ./another_input.sh bạn sẽ thấy.

User input test script option result
User input test script option result

Tại vị trí “read -sp”, do option -s bạn sẽ thấy thông tin password (tôi nhập là “incorrect”) không hiển thị khi người dùng nhập thông tin. Đây là phương thức xử lý nhập liệu password chuẩn cmn mực trên các hệ thống.

Đến đây tôi xin dừng nội dung chém gió kỳ này. Kỳ tới tới tôi sẽ chuyển sang mấy thứ cao sang hơn như đám Conditional statements của Bash script.

2 thoughts on “Bash Script – La liếm với bộ 3 Variable, Argument & User Input”

Leave a Reply

Your email address will not be published. Required fields are marked *