LẬP TRÌNH TRONG MÔI TRƯỜNG SHELL 2.1 Mục tiêu Bài thực hành này giúp sinh viên: ● Làm quen và tìm hiểu cách sử dụng ngôn ngữ shell để lập trình ● Thực hành lập trình một số cấu trúc điề
LẬP TRÌNH TRONG MÔI TRƯỜNG SHELL
Mục tiêu
Bài thực hành này giúp sinh viên:
● Làm quen và tìm hiểu cách sử dụng ngôn ngữ shell để lập trình
● Thực hành lập trình một số cấu trúc điều khiển cơ bản của shell
● Viết được một số chương trình đơn giản bằng ngôn ngữ shell
Nội dung thực hành
● Thực hành các lệnh tương tác với hệ điều hành Linux thông qua shell
● Tìm hiểu và thực hành ngôn ngữ shell
Sinh viên chuẩn bị
Trong bài thực hành LAB 1, chúng ta đã biết cách sử dụng máy ảo để cài đặt hệ điều hành Ubuntu và thực hành các thao tác cơ bản trên hệ điều hành Có thể thấy, việc sử dụng terminal để gõ lệnh phần nào cũng sẽ mang lại cảm giác nhàm chán, đặc biệt những
2 người mới bắt đầu ít nhiều sẽ gặp khó khăn trong việc soạn thảo các file văn bản, hay file code Phần chuẩn bị này sẽ hướng dẫn sinh viên cách sử dụng công cụ Visual Studio Code làm giao diện tuy đơn giản nhưng vô cùng hiệu quả khi lập trình trong Ubuntu Ngoài ra, quy trình này cũng được áp dụng nhiều trong các doanh nghiệp, do đó, sinh viên sẽ có kinh nghiệm để tự tin hơn trong các công việc sau này
2.3.1 Cài đặt Visual Studio Code
Visual Studio Code (viết tắt là VS Code) là một trình biên tập (editor) rất phổ biến trong cộng đồng các nhà phát triển và lập trình viên Khác với Visual Studio vốn là một IDE có đầy đủ chức năng từ việc viết code, biên dịch, debug, đóng gói, hỗ trợ cho nhiều ngôn ngữ lập trình, VS Code đơn thuần là một trình biên tập được dùng để viết code Việc này làm VS Code khá nhẹ để cài đặt và rất dễ sử dụng Điểm mạnh của VS Code nằm ở khả năng tùy biến theo nhu cầu của người sử dụng, ví dụ, nếu người dùng muốn lập trình C có thể cài đặt trình biên dịch riêng (sẽ trình bày ở LAB 3) và tích hợp vào VS Code, VS Code sẽ hỗ trợ khả năng nhắc lệnh và giao diện tương ứng, điều này làm cho việc viết code, chạy, và debug trở nên dễ dàng hơn Trong bài thực hành này, VS Code được cài đặt và sử dụng như một nơi trung gian để giao tiếp với máy ảo, viết các file kịch bản và thực thi các file kịch bản này
Sinh viên có thể tải VS Code và thực hiện cài đặt theo hướng dẫn tại đây: https://code.visualstudio.com/
Hình 1 Giao diện khởi chạy của VS Code
SSH, hay còn gọi với tên đầy đủ là Secure Shell, là một phương thức đăng nhập từ xa an toàn từ một máy tính đến một máy tính khác Nó cung cấp một số tùy chọn thay thế cho việc xác thực mạnh, bảo vệ tính bảo mật và toàn vẹn của giao tiếp thông qua các phương thức mã hóa mạnh.
SSH thường được doanh nghiệp sử dụng chocác mục đích sau:
● Cung cấp kết nối an toàn cho các người dùng và các tiến trình tự động
● Truyền tập tin tương tác và tự động
● Thực hiện các lệnh từ xa
● Quản lý cơ sở hạ tầng mạng và các thành phần hệ thống quan trọng khác
Trong nhiều tình huống, nhân viên sẽ cần phải thực hiện truy cập từ xa vào server của công ty, do đó, việc biết cài đặt và sử dụng SSH là một trong các kỹ năng cơ bản cần có trong các công ty IT Quy trình kết nối sử dụng SSH được trình bày trong Hình 2
Hình 2 Quy trình kết nối qua phương thức SSH
● Bước 1: Client khởi tạp giao tiếp tới server
● Bước 2: Server gửi public key tới client
● Bước 3: Hai bên kiểm tra tham số và mở kênh bảo mật
● Bước 4: User có thể đăng nhập vào server
Để thiết lập kết nối SSH từ xa đến máy chủ, cần cấu hình cả trên máy khách (client) và máy chủ (server) Trong bài thực hành này, chúng ta sẽ sử dụng máy ảo đã tạo ở LAB 1 để mô phỏng quá trình kết nối.
Máy client là máy khởi tạo kết nối từ xa Trong hướng dẫn này, máy tính chính sẽ được sử dụng làm client Máy client có thể chạy bất kỳ hệ điều hành nào bao gồm Windows, macOS hoặc Linux.
● Server: Trong phần thực hành này, ta sẽ dùng máy ảo làm server Như vậy, server hiện đang chạy Linux 2.3.2.1 Cài đặt SSH Client [THỰC HIỆN TRÊN CLIENT]
Trong các hệ điều hành được liệt kê ở trên, nhà phát triển đã mặc định cài đặt OpenSSH một trình điều khiển SSH rất phổ biển -
- sẵn cho người dùng Tuy nhiên, để chắc chắn, ta nên kiểm tra xem máy đã có SSH chưa bằng cách:
● Mở terminal trên MacOS, Ubuntu hoặc cmd/powershell trên Windows
● Nếu shelll không báo lỗi không tìm thấy lệnh và trả về như bên dưới thì có nghĩa là máy đã được cài đặt SSH rồi
Hình 3 Kết quả lệnh ssh trả về trên Windows
Hình 4 Kết quả lệnh ssh trả về Mac
Trong trường hợp máy chưa được cài đặt OpenSSH, thì có thể thực hiện cài đặt như sau:
● Đối với máy Windows: o Vào Settings > Apps >Optional Features o Bấm vào nút Add a feature o Gõ để tìm OpenSSH Client và bấm Install
● Đối với máy Mac: mặc định đã được cài đặt
● Đối với máy Ubuntu: o Gõ lệnh: sudo apt get update- o Gõ lệnh: sudo apt get upgrade- o Gõ lệnh: sudo apt-get install openssh client-
2.3.2.2 Cài đặt SSH Server [THỰC HIỆN TRÊN SERVER]
Như đã trình bày ở trên, máy ảo Ubuntu sẽ được sử dụng để làm server, do đó phần này chỉ hướng dẫn cách để cài đặt và cấu hình SSH Server trên hệ điều hành Ubuntu
● Để cài đặt SSH Server trên Ubuntu ta thực hiện lần lượt các lệnh sau: sudo apt-get update sudo apt-get upgrade sudo apt install openssh-server
● Mặc định nhiều hệ thống sẽ chặn port 22 dùng để giao tiếp SSH, do đó ta cần khai báo với tường lửa cho phép giao tiếp SSH qua port này: sudo ufw allow ssh
● Sau khi cài đặt thành công, ta cần bật SSH trên server lên bằng câu lệnh: sudo service ssh restart
● Sau cùng, để chắc chắn SSH đã chạy, ta kiểm tra lại bằng câu lệnh: sudo service ssh status
Hình 5 Kiểm tra và thấy SSH đang chạy
Dành cho WSL và Multipass:
Mặc định trên WSL và Multipass, user đăng nhập mà không cần nhập mật khẩu, việc này không tuân thủ các nguyên tắc xác thực mạnh của SSH Do đó để sử dụng SSH kết nối đến máy ảo được tạo bởi WSL và Multipass, ta cần thực hiện thêm bước sau đây:
● Mở file ssdh_config bằng lệnh nano: sudo nano /etc/ssh/sshd_config
● Tìm dòng PasswordAuthentication và đặt giá trị là yes
● Tìm dòng KbdInteractiveAuthentication và đặt giá trị là no
● Nếu các dòng trên đang bị comment thì kích hoạt lại bằng cách xóa dấu ở đầu dòng#
Hình 6 Hai dòng màu trắng là hai dòng cần chỉnh lại
Vui lòng xem tại đây: https://averagelinuxuser.com/ssh-into- virtualbox/
Khi cài đặt Port Forwarding thì thiết lập như sau:
Nếu sử dụng Virtual Box, địa chỉ IP kết nối tới máy ảo sẽ là 127.0.0.1
2.3.2.3 Tạo public key trên Client [THỰC HIỆN TRÊN
OpenSSH hỗ trợ nhiều phương thức xác thực khác nhau giữa client và server, trong đó nổi bật nhất là 2 cách sau:
● Xác thực bằng mật khẩu
● Xác thực bằng public key Đây là phương pháp bảo mật thay thế cho việc sử dụng mật khẩu và được khuyến khích sử dụng trên VPS, Cloud, hay thậm chí là server dân dụng
Phần này sẽ hướng dẫn sinh viên cách tạo public key và sử dụng nó để truy cập vào SSH Server
● Bước 1: Kiểm tra xem trong thư mục người dùng đã có thư mục ssh chưa, nếu chưa thì tạo thư mục này
(Trong Windows thì có thể tạo thư mục ssh trong thư mục C:\Users\): mkdir -p ~/.ssh chmod 0700 ~/.ssh
● Bước 2: Tạo cặp key (public - private): ssh-keygen -t rsa
Trong bước này, ta cần phải đặt tên cho file key và chọn nơi lưu nó (khuyến khích chọn mặc định theo đề xuất của chương trình)
Hình 7 Tạo cặp key bằng lệnh
Ngoài ra, trình tạo key cũng sẽ hỏi nếu người dùng nhập passphrase (mật khẩu) cho cặp key, bỏ trống nếu không muốn đặt mật khẩu
Sau khi tạo xong, 02 file sẽ được tạo ra bao gồm ~/.ssh/id_rsa và ~/.ssh/id_rsa.pub lần lượt là private key và pubic key của Client
● Bước 3a (MacOS/Linux): Cài đặt public key cho SSH Server bằng lệnh (thực hiện trên Client): ssh-copy-id -i ~/.ssh/id_rsa.pub [user]@[host]
Trong đó: o ~/.ssh/id_rsa.pub: là đường dẫn đến public key, nếu sinh viên không lưu trong thư mục trên, vui lòng ghi đúng lại thư mục mà sinh viên lưu public key
12 o [user]: là username dùng để đăng nhập máy ảo o [host]: địa chỉ IP hoặc tên miền trỏ tới máy ảo Để tìm địa chỉ IP này, trong máy ảo, cài lệnh ifconfig (sudo apt-get install net-tools) và gõ lệnh ifconfig để xem IP.
Hình 8 Địa chỉ IP của máy ảo
Ví dụ câu lệnh trên có thể được viết thành: ssh-copy-id -i ~/.ssh/id_rsa.pub ubuntu@192.168.64.4
● Bước 3b (Windows): Cài đặt public key cho SSH Server bằng lệnh (thực hiện trên client): scp C:\Users\[username]\.ssh\id_rsa.pub
[user]@[host]:~/.ssh/authorized_keys
13 o Tương tự như trên, thay [username] [user], , và [host]bằng thông tin tương ứng. o Nếu bị báo lỗi thư mục ssh/ không tồn tại, thì tạo thư mục bên máy ảo rồi thực hiện lại bước trên
Khi thực hiện các thao tác trên, hãy đảm bảo rằng SSH Server đã được bật theo hướng dẫn ở mục 2.3.2.2
2.3.2.4 Kết nối từ Client đến Server
Cuối cùng, sau khi đã thực hiện cấu hình các bước trên, ta có thể thực hiện kết nối SSH từ lient đến erver (máy ảo) thông qua VS c s Code
Hướng dẫn thực hành
2.4.1 Sử dụng shell như ngôn ngữ lập trình
Shell có thể được sử dụng như một ngôn ngữ lập trình Có hai cách để viết chương trình điều khiển shell Cách thứ nhất là gõ chương trình ngay từ cửa sổ dòng lệnh, đây cũng là cách đơn giản nhất Tuy nhiên một khi đã thành thạo có thể gộp các lệnh vào một tệp để chạy (chúng tương đương với cách DOS gọi tệp *.bat), cách này hiệu quả và tận dụng triệt để tính năng tự động hóa của shell 2.4.1.1 Điều khiển shell từ dòng lệnh
Chúng ta hãy bắt đầu với ví dụ đơn giản sau Giả sử trên đĩa cứng có rất nhiều file mã nguồn c, bạn muốn truy tìm và hiển thị nội dung của các tệp nguồn chứa chuỗi main() Thay vì dùng lệnh grep để tìm ra từng file sau đó quay lại dùng lệnh more để hiển thị file, ta có thể dùng lệnh điều khiển shell tự động như sau: for file in * do if grep -l 'main( )' $file then more $f le i fi done
Khi gõ một lệnh chưa hoàn chỉnh từ dấu nhắc của shell, shell sẽ chuyển dấu nhắc thành >, shell chờ nhập đầy đủ các lệnh trước khi
Vòng lặp for thực hiện lệnh trong phần thân lệnh cho đến khi đáp ứng điều kiện đã cho Shell tự động hiểu lệnh for bắt đầu khi nào và kết thúc khi nào Ví dụ, lệnh for do sẽ kết thúc khi gặp done Khi gõ done, shell sẽ bắt đầu thực thi tất cả những gì đã nhập vào lệnh sau for Trong ví dụ trên, file là biến shell trong khi * là tập hợp đại diện cho các tên tệp trong thư mục hiện hành.
Bất tiện của việc điều khiển ngôn ngữ shell từ dòng lệnh là khó lấy lại khối lệnh trước đó để sửa đổi và thực thi một lần nữa Nếu ta nhấn phím up/down thì shell có thể trả lại khối lệnh như sau:
$ for file in * ; do ; if grep -1 'main( )' $file; then ; more $file; fi; done Đây là cách các shell Linux vẫn thường làm để cho phép thực thi nhiều lệnh cùng lúc ngay trên dòng lệnh Các lệnh có thể cách nhau bằng dấu (;) Ví dụ:
$ mkdir myfolđer; cd myfolder; sẽ tạo thư mục myfolder bằng lệnh mkdir sau đó chuyển vào thư mục này bằng lệnh cd Chỉ cần gõ Enter một lần duy nhất để thực thi hai lệnh cùng lúc Tuy nhiên sửa chữa các khối lệnh như vậy không dễ dàng và rất dễ gây lỗi Chúng chỉ thuận tiện khi kết hợp khoảng vài ba lệnh Để dễ bảo trì, bạn có thể đưa các lệnh vào một tập tin và yêu cầu shell đọc nội dung tập tin để thực thi lệnh Những tập tin như vậy gọi là tập tin kịch bản (shell script) 2.4.1.2 Điều khiển shell bằng tập tin kịch bản (script file)
Trước hết bạn dùng lệnh $cat > first.sh hay các trình soạn thảo (vi, emacs mc, , nano, gedit) để soạn nội dung tập tin first.sh như sau:
# Script này s tìm trong các file ẽ ở thư mụ c hi n hành ệ
# có ch a main( ) hay không, n i dung c a file s ứ ộ ủ ẽ được
# hi n th ể ị ra màn hình n u tìm th y ế ấ for file in * do if grep -l 'main( )' $file then more $file fi done exit 0
Không như chú thích của C, một dòng chú thích (comment) trong ngôn ngữ shell bắt đầu bằng ký tự # Tuy nhiên, ở đây có một chú thích hơi đặc biệt đó là #!/bin/sh Đây thực sự không phải là chú thích Cặp ký tự #! là chỉ thị yêu cầu shell hiện tại triệu gọi shell sh nằm trong thư mục /bin Shell sh sẽ chịu trách nhiệm thông dịch các lệnh nằm trong tập tin script được tạo
Có thể chỉ định #!/bin/bash làm shell thông dịch thay cho sh, vì trong Linux thật ra sh và bash là một Tuy nhiên như đã nêu, trên các hệ Unix vẫn sử dụng shell sh làm chuẩn, vì vậy vẫn là một thói
Shell sh là một công cụ quen thuộc và hữu ích cho các lập trình viên khi làm việc với hệ điều hành UNIX Sử dụng shell sh cho phép chạy các tập lệnh trong một môi trường làm việc riêng biệt, giúp tránh những thay đổi môi trường do tập lệnh gây ra ảnh hưởng đến môi trường làm việc chính Điều này đảm bảo sự ổn định và tính nhất quán trong quá trình làm việc.
Chỉ thị #! còn được dùng để gọi bất kỳ chương trình nào ta muốn chạy trước khi script tiếp theo được dịch Lệnh exit bảo đảm rằng script sau khi thực thi sẽ trả về mã lỗi, đây là cách mà hầu hết các chương trình nên làm, mặc dù mã lỗi trả về ít khi được dùng đến trong trường hợp thực hiện tương tác trực tiếp từ dòng lệnh Tuy nhiên, việc nhận biết mã trả về của một đoạn script sau khi thực thi lại thường rất có ích nếu bạn triệu gọi script từ trong một script khác Trong đoạn chương trình trên, lệnh exit sẽ trả về 0, cho biết script thực thi thành công và thoát khỏi shell gọi nó Mặc dù khi đã lưu tập tin script với tên sh, nhưng UNIX và Linux không bắt buộc điều này Hiếm khi Linux sử dụng phần đuôi mở rộng của tập tin làm dấu hiệu nhận dạng, do đó tên tệp script có thể là tùy ý Tuy vậy sh vẫn là cách chúng ta nhận ngay ra một tập tin có thể là script của shell một cách nhanh chóng
Chúng ta vừa tạo ra tập tin script first.sh, nó có thể được gọi thực thi theo hai cách Cách đơn giản nhất là gọi trình shell với tên tập tin script làm đối số Ví dụ:
Cách gọi trên là bình thường, nhưng vẫn quen thuộc hơn nếu ta có thể gọi first.sh ngay từ dòng lệnh, tương tự các lệnh Linux thông thường Để làm được điều này, trước hết cần chuyển thuộc tính thực thi (x) cho tập tin script bằng lệnh chmod như sau:
Sau đó có thể triệu gọi script theo cách thứ hai tiện lợi hơn:
Có thể lệnh trên không thực hiện thành công và ta sẽ nhận được thông báo lỗi 'command not found' (không tìm thấy lệnh) Điều này xảy ra bởi vì biến môi trường PATH thường không chứa đường dẫn hay vị trí thư mục hiện hành Để khắc phục, ta có thể thêm vào biến môi trường PATH đường dẫn thư mục hiện hành như sau:
Nếu muốn Linux tự động nhớ thư mục hiện hành mỗi khi đăng nhập bạn có thể thêm lệnh PATH=$PATH : vào cuối tệp bash_profile (file được triệu gọi lúc hệ thống đăng nhập tương - tự autoexec.bat của DOS) Tuy nhiên cách ngắn gọn và đơn giản nhất mà ta vẫn thường làm là định rõ dấu thư mục hiện hành / ngay trên lệnh Ví dụ:
Lưu ý: Đối với tài khoản root, không nên thay đổi biến môi trường PATH (bằng cách thêm dấu chỉ định ) cho phép truy tìm thư mục hiện hành Điều này không an toàn và dễ tạo ra lỗ hổng bảo mật Ví dụ, một quản trị hệ đăng nhập dưới quyền root, triệu gọi
Bài tập thực hành
1 Chạy tất cả các đoạn lệnh ví dụ ở phần 2.4 Chụp hình kết quả chạy các file script và lưu vào báo cáo
2 Viết chương trình cho phép nhập vào tên và mssv Kiểm tra nếu mssv đó không trùng với mình thì bắt nhập lại In ra màn hình kết quả
3 Viết chương trình cho phép nhập vào một số n Kiểm tra nếu n < 10 thì bắt nhập lại Tính tổng các số từ 1 đến n In kết quả ra màn hình
4 Viết trình cho phép nhập vào một chuỗi Kiểm tra chuỗi đó có tồn tại trong một file text (ví dụ test.txt) cùng thư mục hay không.
Bài tập ôn tập
1 Tìm hiểu về việc cài đặt lệnh git, sử dụng git để tải thư mục ảnh tại đây: https://github.com/locth/OS_LAB2_IMG.git
Viết một file kịch bản để làm những công việc sau: a Kiểm tra trong thư mục người dùng, nếu thấy thư mục PNG và JPG chưa tồn tại thì tạo 02 thư mục này b Di chuyển tất cả file PNG trong thư mục ảnh ở trên vào thư mục PNG Xuất ra màn hình số lượng ảnh PNG
59 c Di chuyển tất cả file JPG trong thư mục ảnh ở trên vào thư mục JPG Xuất ra màn hình số lượng ảnh JPG
2 Tạo ra một file text tên monhoc.txt chứa danh sách mã môn học của sinh viên trong học kỳ này, mỗi mã nằm trên một dòng Viết một file kịch bản thực hiện các việc sau: a Yêu cầu người dùng nhập vào họ và tên (không dấu), tạo ra thư mục có tên tương ứng với thông tin người dùng vừa nhập b Đọc file text monhoc.txt ở trên, ở trong thư mục vừa tạo ở câu a, với mỗi môn học, tạo ra một thư mục có tên tương ứng với mã môn đó.