Ở trong buổi học này, chúng tôi sẽ trình bày vài điều cơ bản trong việc sử dụng bash như một ngôn ngữ kịch bản và giới thiệu một số công cụ của shell được sử dụng thường xuyên trên môi trường dòng lệnh trong các công việc hằng ngày của bạn.
Shell Scripting - Ngôn ngữ kịch bản Shell
Chúng ta đã làm quen với việc thực hiện các lệnh bằng shell [vỏ] và pipe [liên kết] chúng lại với nhau thành một quy trình. Tuy nhiên, trong một vài trường hợp, bạn sẽ cần phải thực thi hàng loạt câu lệnh và sử dụng các cấu trúc điều khiển như câu điền kiện hoặc vòng lặp.
Ngôn ngữ shell là bước tiếp theo để có thể sử dụng những thứ phức tạp hơn. Hầu hết các shell đều có một ngôn ngữ kịch bản riêng với những cú pháp riêng biệt để tương tác với biến, cấu trúc điều khiển.Điều đặc biệt khiến ngôn ngữ shell khác biệt khi so sánh chúng với các ngôn ngữ kịch bản khác chính là ngôn ngữ shell đã được tối ưu cho việc thực thi các tác vụ liên quan tới shell [ở môi trường dòng lệnh]. Do đó, việc tạo quy trình cho lệnh [pipe], lưu kết quả vào file, đọc dữ liệu từ thiết bị nhập chuẩn là những thứ nguyên thuỷ trong khi viết shell, điều này khiến shell script dễ dàng để sử dụng hơn là những ngôn ngũ kịch bản tổng quát. Ở trong phần này chúng ta sẽ sử dụng bash để lập trình shell vì bash rất phổ biến.
Ghi chú [người dịch]:
- pipeline: Đối với ngành khoa học máy tính, một pipeline là một sự liên kết các tác vụ được sắp xếp sao cho đầu ra của một tác vụ trong quy trình sẽ là đầu vào của tác vụ tiếp theo. Các bạn có thể hiểu pipeline là quy trình. pipe là cách kết nối các tác vụ để tạo nên một pipeline. Trong ngữ cảnh của shell, các tác vụ này có thể hiểu đơn giản là các command [lệnh].
Để gán giá trị cho biến bằng bash, sử dụng cú pháp
mcd [] {
mkdir -p "$1"
cd "$1"
}
1 và truy cập giá trị của biến bằng cú pháp
mcd [] {
mkdir -p "$1"
cd "$1"
}
2. Lưu ý
mcd [] {
mkdir -p "$1"
cd "$1"
}
3 sẽ không chạy bởi vì câu lệnh sẽ được biên dịch thành việc gọi chương trình
mcd [] {
mkdir -p "$1"
cd "$1"
}
4 với đối số là
mcd [] {
mkdir -p "$1"
cd "$1"
}
5 và
mcd [] {
mkdir -p "$1"
cd "$1"
}
6. Tóm lại, dấu khoảng cách đóng vai trò dấu phân cách các đối số trong các ngôn ngữ shell. Việc này có thể sẽ hơi khó hiểu và gây nhầm lẫn ở giai đoạn đầu, nên hãy luôn kiểm tra việc này.
Chuỗi có thể được khai báo bằng dấu
mcd [] {
mkdir -p "$1"
cd "$1"
}
7 và
mcd [] {
mkdir -p "$1"
cd "$1"
}
8 trong bash, nhưng chúng không bằng nhau. Chuỗi được khai báo bằng
mcd [] {
mkdir -p "$1"
cd "$1"
}
7 là chuỗi theo nghĩa đen [giá trị cụ thể] và sẽ không được thay thế bằng các giá trị của biến, trong khi chuỗi được khai báo bằng
mcd [] {
mkdir -p "$1"
cd "$1"
}
8 thì có.
foo=bar
echo "$foo"
# prints bar
echo '$foo'
# prints $foo
Như hầu hết các ngôn ngữ lập trình khác, bash cũng hỗ trợ các cấu trúc điều khiển như
false || echo "Oops, fail"
# Oops, fail
true || echo "Will not be printed"
#
true && echo "Things went well"
# Things went well
false && echo "Will not be printed"
#
true ; echo "This will always run"
# This will always run
false ; echo "This will always run"
# This will always run
1,
false || echo "Oops, fail"
# Oops, fail
true || echo "Will not be printed"
#
true && echo "Things went well"
# Things went well
false && echo "Will not be printed"
#
true ; echo "This will always run"
# This will always run
false ; echo "This will always run"
# This will always run
2,
false || echo "Oops, fail"
# Oops, fail
true || echo "Will not be printed"
#
true && echo "Things went well"
# Things went well
false && echo "Will not be printed"
#
true ; echo "This will always run"
# This will always run
false ; echo "This will always run"
# This will always run
3 và
false || echo "Oops, fail"
# Oops, fail
true || echo "Will not be printed"
#
true && echo "Things went well"
# Things went well
false && echo "Will not be printed"
#
true ; echo "This will always run"
# This will always run
false ; echo "This will always run"
# This will always run
4. Và tất nhiên,
false || echo "Oops, fail"
# Oops, fail
true || echo "Will not be printed"
#
true && echo "Things went well"
# Things went well
false && echo "Will not be printed"
#
true ; echo "This will always run"
# This will always run
false ; echo "This will always run"
# This will always run
5 hỗ trợ các hàm nhận vào các đối số và thực hiện các tác vụ. Đây là một ví dụ về hàm có chức năng là tạo một thư mục và
false || echo "Oops, fail"
# Oops, fail
true || echo "Will not be printed"
#
true && echo "Things went well"
# Things went well
false && echo "Will not be printed"
#
true ; echo "This will always run"
# This will always run
false ; echo "This will always run"
# This will always run
6 vào nó.
mcd [] {
mkdir -p "$1"
cd "$1"
}
Ở đây
false || echo "Oops, fail"
# Oops, fail
true || echo "Will not be printed"
#
true && echo "Things went well"
# Things went well
false && echo "Will not be printed"
#
true ; echo "This will always run"
# This will always run
false ; echo "This will always run"
# This will always run
7 mang ý nghĩa là đối số được truyền vào đầu tiên cho hàm. Không như các ngôn ngữ khác,
false || echo "Oops, fail"
# Oops, fail
true || echo "Will not be printed"
#
true && echo "Things went well"
# Things went well
false && echo "Will not be printed"
#
true ; echo "This will always run"
# This will always run
false ; echo "This will always run"
# This will always run
5 sử dụng một tập hợp các biến đặc biệt để chỉ đến các đối số, mã lỗi và các biến liên quan. Ở dưới là một danh sách của chúng. Các bạn có thể tìm một danh sách đầy đủ và chi tiết hơn ở đây.
9 - Tên của shell hoặc tên của shell scriptfalse || echo "Oops, fail"
Oops, fail
true || echo "Will not be printed"
true && echo "Things went well"
Things went well
false && echo "Will not be printed"
true ; echo "This will always run"
This will always run
false ; echo "This will always run"
This will always run
false || echo "Oops, fail"
Oops, fail
true || echo "Will not be printed"
true && echo "Things went well"
Things went well
false && echo "Will not be printed"
true ; echo "This will always run"
This will always run
false ; echo "This will always run"
This will always run
7 tới
#!/bin/bash echo "Starting program at $[date]" # Date will be substituted echo "Running program $0 with $# arguments with pid $$" for file in "$@"; do
donegrep foobar "$file" > /dev/null 2> /dev/null # When pattern is not found, grep has exit status 1 # We redirect STDOUT and STDERR to a null register since we do not care about them if [[ $? -ne 0 ]]; then echo "File $file does not have any foobar, adding one" echo "# foobar" >> "$file" fi
1 - Các đối số của lệnh
7 là đầu tiên và tiếp tục.false || echo "Oops, fail"
Oops, fail
true || echo "Will not be printed"
true && echo "Things went well"
Things went well
false && echo "Will not be printed"
true ; echo "This will always run"
This will always run
false ; echo "This will always run"
This will always run
3 - Tất cả đối số#!/bin/bash echo "Starting program at $[date]" # Date will be substituted echo "Running program $0 with $# arguments with pid $$" for file in "$@"; do
donegrep foobar "$file" > /dev/null 2> /dev/null # When pattern is not found, grep has exit status 1 # We redirect STDOUT and STDERR to a null register since we do not care about them if [[ $? -ne 0 ]]; then echo "File $file does not have any foobar, adding one" echo "# foobar" >> "$file" fi
4 - Số lượng đối số#!/bin/bash echo "Starting program at $[date]" # Date will be substituted echo "Running program $0 with $# arguments with pid $$" for file in "$@"; do
donegrep foobar "$file" > /dev/null 2> /dev/null # When pattern is not found, grep has exit status 1 # We redirect STDOUT and STDERR to a null register since we do not care about them if [[ $? -ne 0 ]]; then echo "File $file does not have any foobar, adding one" echo "# foobar" >> "$file" fi
5 - Mã kết quả của lệnh trước [thành công hay thất bại]#!/bin/bash echo "Starting program at $[date]" # Date will be substituted echo "Running program $0 with $# arguments with pid $$" for file in "$@"; do
donegrep foobar "$file" > /dev/null 2> /dev/null # When pattern is not found, grep has exit status 1 # We redirect STDOUT and STDERR to a null register since we do not care about them if [[ $? -ne 0 ]]; then echo "File $file does not have any foobar, adding one" echo "# foobar" >> "$file" fi
6 - PID [Process identification number ] của lệnh#!/bin/bash echo "Starting program at $[date]" # Date will be substituted echo "Running program $0 with $# arguments with pid $$" for file in "$@"; do
donegrep foobar "$file" > /dev/null 2> /dev/null # When pattern is not found, grep has exit status 1 # We redirect STDOUT and STDERR to a null register since we do not care about them if [[ $? -ne 0 ]]; then echo "File $file does not have any foobar, adding one" echo "# foobar" >> "$file" fi
#!/bin/bash echo "Starting program at $[date]" # Date will be substituted echo "Running program $0 with $# arguments with pid $$" for file in "$@"; do
donegrep foobar "$file" > /dev/null 2> /dev/null # When pattern is not found, grep has exit status 1 # We redirect STDOUT and STDERR to a null register since we do not care about them if [[ $? -ne 0 ]]; then echo "File $file does not have any foobar, adding one" echo "# foobar" >> "$file" fi
7 - Chỉ đến lệnh phía trước, tính cả tham số. Một cách sử dụng cơ bản của nó là thực hiện lệnh nếu lệnh trước đó thất bại bởi vì thiếu quyền truy cập[permission denied]. Bạn có thể tái thực hiện lệnh với quyền sudo bằng cách
8.#!/bin/bash echo "Starting program at $[date]" # Date will be substituted echo "Running program $0 with $# arguments with pid $$" for file in "$@"; do
donegrep foobar "$file" > /dev/null 2> /dev/null # When pattern is not found, grep has exit status 1 # We redirect STDOUT and STDERR to a null register since we do not care about them if [[ $? -ne 0 ]]; then echo "File $file does not have any foobar, adding one" echo "# foobar" >> "$file" fi
#!/bin/bash echo "Starting program at $[date]" # Date will be substituted echo "Running program $0 with $# arguments with pid $$" for file in "$@"; do
donegrep foobar "$file" > /dev/null 2> /dev/null # When pattern is not found, grep has exit status 1 # We redirect STDOUT and STDERR to a null register since we do not care about them if [[ $? -ne 0 ]]; then echo "File $file does not have any foobar, adding one" echo "# foobar" >> "$file" fi
9 - Đối số cuối cùng của lệnh phía trước. nếu bạn đang sử dụng shell bằng chế độ tương tác trực tiếp, bạn có thể lấy giá trị này bằng việc gõ
convert image.{png,jpg}
Will expand to
convert image.png image.jpg cp /path/to/project/{foo,bar,baz}.sh /newpath
Will expand to
cp /path/to/project/foo.sh /path/to/project/bar.sh /path/to/project/baz.sh /newpath
Globbing techniques can also be combined
mv {.py,.sh} folderWill move all .py and *.sh files
mkdir foo bar
This creates files foo/a, foo/b, ... foo/h, bar/a, bar/b, ... bar/h
touch {foo,bar}/{a..h} touch foo/x bar/y
Show differences between files in foo and bar
diff