Trong phần tiếp theo của chuỗi bài viết chuyên sâu về dòng lệnh Bash, chúng ta sẽ cùng khám phá kỹ thuật grep nâng cao để trích xuất chính xác nội dung cần thiết, đi kèm với hướng dẫn cách sử dụng pwd
nhằm xác định đúng thư mục nơi một Bash script được khởi chạy.
DataOnline sẽ hướng dẫn bạn cách học :
- Các mẹo, thủ thuật và phương pháp hiệu quả khi dùng dòng lệnh Bash
- Cách tương tác nâng cao với Bash shell
- Cách cải thiện toàn diện kỹ năng Bash và trở thành người dùng Bash chuyên nghiệp hơn
Yêu cầu phần mềm và quy ước sử dụng
Danh mục | Yêu cầu, quy ước hoặc phiên bản phần mềm được sử dụng |
---|---|
Hệ thống | Linux – không phụ thuộc vào bản phân phối |
Phần mềm | Bash command line, hệ điều hành nền tảng Linux |
Khác | Bất kỳ tiện ích nào không được tích hợp sẵn trong Bash có thể cài đặt bằng sudo apt-get install utility-name (hoặc yum install trên hệ RedHat) |
Các quy ước
#
– yêu cầu lệnh được thực thi với quyền root (trực tiếp hoặc dùngsudo
)$
– lệnh được chạy với quyền người dùng thường
Ví dụ 1: Đường dẫn thư mục làm việc – Có đúng như bạn nghĩ?
Chúng ta thường sử dụng lệnh pwd
trong dòng lệnh để biết thư mục hiện tại:
$ pwd /home/roel/workspace
Nhưng nếu ta muốn lấy thư mục mà một script được khởi chạy từ đó, liệu cách sử dụng biến trong script có cho ra kết quả tương tự?
$ cat test_pwd.sh #!/bin/bash MY_PATH1="${PWD}" echo "${MY_PATH1}" MY_PATH2="$(pwd)" echo "${MY_PATH2}"
Trong ví dụ này, ta dùng hai cách để lấy đường dẫn:
MY_PATH1
sử dụng biến$PWD
– biến môi trường tự động có sẵnMY_PATH2
dùng kết quả thực thi lệnhpwd
trong subshell$(...)
Kết quả khi chạy script:
$ ./test_pwd.sh /home/roel/workspace /home/roel/workspace
Mọi thứ có vẻ ổn. Nhưng khi chúng ta chuyển sang một thư mục khác và gọi script bằng đường dẫn tương đối hoặc đầy đủ, thì pwd
hoặc $PWD
bên trong script sẽ trả về thư mục chúng ta đang đứng lúc gọi, chứ không phải nơi script thật sự nằm.
$ mkdir test $ cd test $ ../test_pwd.sh /home/roel/workspace/test /home/roel/workspace/test
Bạn thấy đấy, pwd
hay $PWD
sẽ luôn trả về đường dẫn hiện tại, chứ không phải nơi script đang cư trú.
Vấn đề này khá phổ biến trong các Bash script phức tạp có nhiều script con hoặc các file cấu hình đi kèm. Vậy làm thế nào để lấy chính xác đường dẫn nơi script được khởi chạy từ đó?
Hướng tiếp cận 1 – Dùng dirname "$0"
$ cat test2.sh #!/bin/bash echo "\$0" dirname "\$0"
$0
là một biến đặc biệt, chứa tên script khi được khởi chạy. dirname
sẽ lấy ra phần thư mục từ tên file được truyền vào.
Thử chạy:
$ ./test2.sh ./test2.sh . $ cd test $ ../test2.sh ../test2.sh ..
Cách này tốt hơn, nhưng vẫn chưa phải là đường dẫn tuyệt đối.
Hướng tiếp cận 2 – Dùng cd "$(dirname "$0")" && pwd
Giải pháp lý tưởng: bao dirname
bên trong cd
, sau đó dùng pwd
để lấy đường dẫn tuyệt đối:
$ cat make_it_work.sh #!/bin/bash MY_PATH="$(cd "$(dirname "\$0")" && pwd)" echo "${MY_PATH}"
Chạy thử:
$ ./make_it_work.sh /home/roel/workspace
Giờ ta thử chạy từ thư mục con:
$ cd test && pwd /home/roel/workspace/test $ ../make_it_work.sh /home/roel/workspace $ /home/roel/workspace/make_it_work.sh /home/roel/workspace
Hoàn hảo!
Trong cả hai trường hợp – dù bạn gọi script bằng cách tương đối (../) hay bằng đường dẫn đầy đủ (/home/roel/workspace/
), thì kết quả thu được vẫn là thư mục nơi script được khởi chạy (/home/roel/workspace/
), chứ không phải thư mục làm việc hiện tại, hay giá trị trả về từ pwd
(/home/roel/workspace/test
).
Tóm lại, bạn có thể sử dụng đoạn lệnh một dòng MY_PATH="$(cd "$(dirname "$0")" && pwd)"
trong script để lấy chính xác đường dẫn tuyệt đối của thư mục chứa script. Sau đó, việc sử dụng đường dẫn tương đối dựa trên biến này sẽ rất dễ dàng và hiệu quả. Ví dụ, bạn có thể gọi đến ${MY_PATH}/include/mysubscript.sh
hoặc thậm chí ${MY_PATH}/../one_dir_up_file.txt
một cách an toàn.
Ví dụ 2: Grep chính xác thứ bạn cần
Chắc hẳn bạn đã dùng grep
– một công cụ cực kỳ mạnh mẽ để tìm kiếm chuỗi văn bản trong file.
$ cat test line 1 my line line 2 your lines line 3 our line $ grep 'line 2' test line 2 your lines
Chúng ta có một file đầu vào gồm 3 dòng, và đang tìm kiếm một dòng cụ thể (line 2) trong file đó. Nhưng giả sử bạn chỉ muốn lấy những dòng có chứa dạng số nhiều của từ “line”, tức là “lines” thì sao? Và nếu bạn chỉ muốn lấy đúng từ đứng trước nó – kèm theo từ “lines” – nhưng không cần toàn bộ dòng chứa “line x” thì xử lý như thế nào?
Trong trường hợp này, chúng ta có thể sử dụng grep
kết hợp với tham số -o
(viết tắt của “only”) để chỉ in ra phần phù hợp mà ta cần:
$ grep -o 'lines' test lines $ grep -o '\w\+ lines' test your lines
Bingo! Đầu tiên, ta tìm đúng từ ‘lines’, và nó được in ra. Sau đó, ta bổ sung phía trước một khoảng trắng cùng với biểu thức chính quy để chỉ định như sau (theo ngôn ngữ mô tả giả lập):
- Tìm một từ (
\w
) – tức là tập hợp các ký tự chữ và số - Với điều kiện từ đó xuất hiện ít nhất một lần hoặc nhiều hơn (
\+
) - Tiếp theo là dấu cách
- Và kết thúc bằng từ lines
Kết luận
Đọc đến đây, bạn đã được hướng dẫn cách xác định chính xác thư mục chứa script bằng cách kết hợp linh hoạt giữa dirname
và pwd
, giúp truy xuất đường dẫn tuyệt đối một cách hiệu quả – bất kể script được gọi bằng đường dẫn tương đối hay tuyệt đối. Bên cạnh đó, bạn cũng học được cách tinh chỉnh lệnh grep
với tham số -o
và biểu thức chính quy để trích xuất chính xác nội dung mong muốn thay vì toàn bộ dòng – một kỹ thuật đơn giản nhưng cực kỳ hữu ích trong xử lý văn bản và phân tích log trong môi trường Bash.
Các ví dụ về mẹo và thủ thuật dòng lệnh Bash hữu ích – Phần 1
Các ví dụ về mẹo và thủ thuật dòng lệnh Bash hữu ích – Phần 2
Các ví dụ về mẹo và thủ thuật dòng lệnh Bash hữu ích – Phần 3
Các ví dụ về mẹo và thủ thuật dòng lệnh Bash hữu ích – Phần 4
Các ví dụ về mẹo và thủ thuật dòng lệnh Bash hữu ích – Phần 5