Open(MAIL, “| mail Địa_chỉ_bạn_ở đây”);

Một phần của tài liệu Lịch sử của perl (Trang 26 - 30)

print MAIL “tin xu: $somename đã đoán $someguess\n”; 0; # cho li giá tr false

} }

Câu lệnh mới thứ nhất ở đây là open(), mà có một kí hiệu đường ống (|) trong tên tệp. Đây là một chỉ dẫn đặc biệt rằng ta đang mở một chỉ lệnh thay vì một tệp. Vì đường ống là tại chỗ bắt đầu của chỉ lệnh nên ta đang mở một chỉ

lệnh để ta có thể ghi lên nó. (nếu bạn đặt đường ống tại cuối thay vì đầu thì bạn có thể đọc cái ra của chỉ lệnh.)

Câu lệnh tiếp, print, chỉ ra rằng một tước hiệu tệp giữa từ khoá print và giá trị được in ra chọn tước hiệu tệp đó làm cái ra, thay vì STDOUT* . Điều này có nghĩa là thông báo sẽ kết thúc như cái vào cho chỉ lệnh mail.

Cuối cùng, ta đóng tước hiệu tệp, mà sẽ bắt đầu để mail gửi dữ liệu của nó theo cách của nó.

Để cho đúng, chúng ta có thể gửi câu trả lời đúng cũng như câu trả lời sai, nhưng rồi ai đó đọc qua vai tôi (hay núp trong hệ thống thư) trong khi tôi đang

đọc thư mà có thể lấy quá nhiều thông tin có ích.

Perl có thể cũng gọi cả các lệnh với việc kiểm soát chính xác trên danh sách

đối, mở các tước hiệu tệp, hay thậm chí lôi ra cả bản sao của chương trình hiện tại, và thực hiện hai (hay nhiều) bản sao song song. Backquotes (giống như

backquotes của vỏ) cho một cách dễ dàng nắm được cái ra của một chỉ lệnh như

dữ liệụ Tất cả những điều này sẽ được mô tả trong Chương 14, Quản lí tiến trình, cho nên bạn nhớđọc.

Nhiều tệp từ bí mật trong danh mục hiện tại

Ta hãy thay đổi định nghĩa của tên tệp từ bí mật một chút. Thay vì tệp được

đặt tên là wordslist, thì ta hãy tìm bất kì cái gì trong danh mục hiện tại mà có tận cùng là .secret. Với lớp vỏ, ta nói:

echo *.secret

để thu được một liệt kê ngắn gọn cho tất cả các tên nàỵ Như lát nữa bạn sẽ thấy, Perl dùng một cú pháp tên chùm tương tự.

Ta lấy lại định nghĩa &init_words :

sub init_words {

while ($filename = <*.secret>) {

open (WORDSLIST, $filename);

if (-M WORDSLIST > 7) {

while ($name = <WORDSLIST>) {

chop ($name); $word = <WORDSLIST>; chop($word); $words{$name} = $word; } } close (WORDSLIST); } }

Trước hết, tôi đã bao một chu trình while mới quanh phần lớn chương trình con của bản cũ. Điều mới ở đây là toán tử <*.secret>. Điều này được gọi là núm tên tệp, bởi lí do lịch sử. Nó làm việc rất giống <STDIN>, ở chỗ mỗi lần

được thâm nhập tới, nó đều cho lại giá trị tiếp: tên tệp kế tiếp sánh với mẫu của vỏ, trong trường hợp này là *.secret. Khi không có tên tệp thêm nữa được cho lại thì núm tên tệp cho xâu rỗng* .

Cho nên nếu danh mục hiện tại có chứa fred.secret và barneỵsecret, thì

$filename là barneỵsecret ở bước đầu qua chu trình while (tên tới theo trật tự

sắp của bảng chữ). Ở bước thứ hai, $filename là fred.secret. Và không có tình huống thứ ba vì núm cho lại xâu rỗng khi lần thứ ba được gọi tới, làm cho chu trình while thành sai, gây ra việc ra khỏi chương trình con.

Bên trong chu trình while, chúng ta mở tệp và kiểm chứng rằng nó đủ gần

đây (ít hơn bẩy ngày từ lần sửa đổi trước). Với những tệp đủ gần, chúng ta duyệt qua như trước.

Chú ý rằng nếu không có tệp nào sánh với *.secret và lại ít hơn bẩy ngày thì chương trình con sẽ ra mà không đặt bất kì từ bí mật nào vào mảng %words.

Điều đó có nghĩa là mọi người sẽ phải dùng từ đồ cáu knh. Thế cũng được. (Với mã thật, tôi sẽ thêm một kiểm tra nào đó về số các ô trong %words trước khi cho lại, và die nếu nó không tốt. Bạn hãy xem toán tử keys() khi ta lấy mảng kết hợp trong Chương 5, Mảng kết hợp.)

* Lại undef lần nữa

Nhưng chúng ta biết họ là ai!

Được rồi, chúng ta đã hỏi tên người dùng khi trong thực tế chúng ta có thể

lấy tên của người dùng hiện tại từ hệ thống, bằng việc dùng một vài dòng như:

@password = getpwuid($<); # ly d liu mt hiu

$name = $password[6]; # ly trường GCOS

$name =~ s/,.*//; # vt đi mi th sau du phy đầu tiên

Dòng đầu tiên dùng số hiệu người dùng ID của UNIX (thường được gọi là

UID), tự động hiện diện trong biến Perl $<. Toán tử getpwuid() (được đặt tên giống như trình thư viện chuẩn) lấy số hiệu UID và cho lại thông tin từ tệp mật hiệu (hay có thể một số cơ sở dữ liệu khác) như một danh sách. Chúng ta đánh dấu thông tin này trong mảng @password.

Khoản mục thứ bẩy của mảng @password (chỉ số 6) là trường GCOS, mà thường là một xâu có chứa danh sách các giá trị các nhau bởi dấu phẩỵ Giá trị đầu tiên của xâu đó thường là tên đầy đủ của ngườị

Một khi hai câu lệnh đầu này đã hoàn tất thì chúng ta có toàn bộ trường GCOS trong $name. Tên đầy đủ chỉ là phần thứ nhất của xâu trước dấu phẩy

đầu tiên, cho nên câu lệnh thứ ba vứt đi mọi thứ sau dấu phẩy thứ nhất.

Gắn tất cả những điều đó với phần còn lại của chương trình (như đã được sửa bởi hai thay đổi chương trình con khác)

#! /usr/bin/perl &init_words;

@password = getpwuid($<); # ly d liu mt hiu

$name = $password[6]; # ly trường GCOS

$name =~ s/,.*//; # vt đi mi th sau du phy đầu tiên

if ($name =~ /^randal\b/i ) { # tr li cách khác

print “Xin chào, Randal! May quá anh đây!\n”; } else { } else {

print “Xin chào, $name!\n”; # chào thông thường

print “T bí mt là gì?” ; $guess = <STDIN>; $guess = <STDIN>; chop($guess);

while ( ! &good_word($name, $guess)) { print “Sai ri, th li đị T bí mt là gì?”; $guess = <STDIN>; chop($guess); } } sub init_words {

while ($filename = <*.secret>) {

if (-M WORDSLIST > 7) {

while ($name = <WORDSLIST>) {

chop ($name); $word = <WORDSLIST>; chop($word); $words{$name} = $word; } } close (WORDSLIST); } } sub good_word {

local($somename, $someguess) = @_; # tên tham biến

$somename =~ s/\W.*//; # b mi th sau t đầu

$somename =~ tr/A-Z/a-z/; # mi th thành ch thường

if ($somename eq “randal”) { # không nên đoán

1; #giá tr cho li là true

} elsif (($words{$somename} || “đồ cáu knh”) eq $someguess) { 1; # giá tr cho li là true

} else {

open(MAIL, “|mail Địa_ch_bn__đây”);

print MAIL “tin xu: $somename đã đoán $someguess\n”; 0; # cho li giá tr false

} }

Chú ý rằng chúng ta không còn cần hỏi người dùng về tên người ấy nữa - chúng ta đã biết nó!

Perl cung cấp nhiều trình thâm nhập cơ sở dữ liệu hệ thống để lôi ra những giá trị từ cơ sở dữ liệu mật hiệu, nhóm, máy chủ, mạng, dịch vụ và giao thức. Cả

việc tra cứu riêng (như được trình bầy ở trên) và việc duyệt số lớn cũng đều

được Perl hỗ trợ.

Liệt kê các từ bí mật

Rồi ông phụ trách danh sách từ bí mật lại muốn có một báo cáo về tất cả

những từ bí mật hiện đang dùng, và chúng cũ đến đâụ Nếu ta gạt sang bên chương trình từ bí mật một lúc, thì ta sẽ có thời gian để viết một chương trình báo cáo cho ông phụ trách.

Trước hết, ta hãy lấy ra tất cả các từ bí mật, bằng việc ăn cắp một đoạn mã trong chương trình con &init_words:

while ($filename = <*.secret>) {

open (WORDSLIST, $filename);

while ($name = <WORDSLIST>) {

chop ($name);

$word = <WORDSLIST>;

chop($word); ### cht liu mi sđưa vào đây

}

}

close (WORDSLIST);

}

Tại điểm có đánh dấu “chất liệu mới sẽđưa vào đây,” ta biết ba điều: tên của tệp (trong $filename), tên một ai đó (trong $name), và rằng từ bí mật của một người (trong $Word). Sau đây là chỗ để dùng công cụ sinh báo cáo của Perl. Ta

định nghĩa một định dạng ở đâu đó trong chương trình (thông thường gần cuối, giống như chương trình con):

format STDOUT =

@<<<<<<<<<<<<<<< @<<<<<<<<<< @<<<<<<<<<<<<<< $filename, $name, $word

.

Định nghĩa định dạng này bắt đầu với format STDOUT =, và kết thúc với một dấu chấm. Hai dòng ở giữa là chính định dạng. Dòng đầu của định dạng này là dòng định nghĩa trường vốn xác định số lượng, chiều dài và kiểu của trường. Với định dạng này, chúng ta có ba trường. Dòng đi sau dòng định nghĩa trường bao giờ cũng là dòng giá trị trường. Dòng giá trị cho một danh sách các biểu thức mà sẽ được tính khi định dạng này được dùng, và kết quả của những biểu thức đó sẽ được gắn vào trong các trường đã được xác định trên dòng trước đó.

Ta gọi định dạng này với toán tử write, như thế này:

#!/usr/bin/perl

while ($filename = <*.secret>) { open (WORDSLIST, $filename); if (-M WORDSLIST < 7) {

while ($name = <WORDSLIST>) {

chop($name);

$word = <WORDSLIST>

chop($word);

Một phần của tài liệu Lịch sử của perl (Trang 26 - 30)

Tải bản đầy đủ (PDF)

(143 trang)