The stream editor sed
Nguồn: Tổng hợp từ cuốn sách “The Unix Programming Environment” của Brian W. Kernighan và Rob Pike.
Bài viết này giới thiệu những chức năng cơ bản nhất của sed, một chương trình xử lí văn bản cực mạnh trong Unix. Bài viết có sử dụng (mà không giải thích chi tiết) một số regular expression (cơ bản) và một số lệnh Unix (cũng cơ bản
)
Cú pháp chung của sed
Cú pháp chung của một lệnh sed là
sed 'danh sách các lệnh' 'danh sách các file đầu vào'
sed sẽ đọc từng dòng của các file đầu vào và thực hiện từng lệnh trong danh sách các lệnh đối với các dòng đó. Sau đó, sed ghi dữ liệu ra vào thiết bị đầu ra chuẩn.
Chẳng hạn, chúng ta có thể thay tất cả các từ UNIX trong một file thành UNIX(TM) bằng câu lệnh sau:
sed 's/UNIX/UNIX(TM)/g' filename
Khi thực hiện lệnh này, sed sẽ:
- Đọc vào từng dòng của filename
- Đối với mỗi dòng đọc vào, sed sẽ thực hiện lệnh s/UNIX/UNIX(TM)/g, tức là thay thế (s = substitute) tất cả (g = global) các từ UNIX bởi UNIX(TM).
s (substitute) là một lệnh của ed, chương trình tiền thân của sed.
Chú ý: sed không thay đổi nội dung của file đầu vào.
Chúng ta luôn sử dụng dấu nháy đơn (single quote) để bao quanh các lệnh của sed nhằm tránh trường hợp các kí tự đặc biệt bị dịch thành ý nghĩa khác bởi shell.
Sau đây là 1 số lệnh sed thú vị!!!
So sánh C++ và C (1) – Classes and methods
Bài viết này là một trong hai bài viết so sánh giữa C và C++ bằng cách so sánh các đoạn mã trong C++ với đoạn mã tương ứng của nó được viết trong C. So sánh này sẽ cho bạn cái nhìn tốt hơn về sự khác biệt của performance giữa C và C++.
Trong bài viết đầu tiên, chúng ta sẽ xem xét ảnh hưởng tới performance của việc thực thi các phương thức trong C++. So sánh này được thực hiện bằng việc so sánh đoạn mã C++ và đoạn mã C tương ứng.
nested class, nested function và một ứng dụng thú vị của function object
Nguồn: http://www.gotw.ca/gotw/058.htm
Bài viết này không trình bày chi tiết về nested class trong C++ mà chỉ tập trung vào các kĩ thuật sử dụng nested class và function object để mô phỏng các nested function, một yếu tố không có trong C++. Các chi tiết về nested class có thể tìm thấy trong nhiều cuốn sách C++ khác, ví dụ cuốn Thinking in C++, tập 1.
Bài viết đưa ra ba câu hỏi và sau đó lần lượt đi tìm các câu trả lời cho chúng. Ba câu hỏi là:
1- Nested class là gì? Tại sao chúng ta cần các nested class?
2- Local class là gì? Tại sao chúng ta cần các local class?
3- Trong C++ không có khái niệm nested function. Bởi vậy, chúng ta không thể viết một đoạn mã như sau
int f( int i )
{
int j = i*2;
int g( int k )
{
return j+k;
}
j += 4;
return g( 3 );
}
Hãy đưa ra một giải pháp mô phỏng các hàm f và g sao cho đạt được một “hiệu ứng” tương tự như đoạn mã trên.
Trả lời
C++ có rất nhiều công cụ hữu ích dùng để ẩn thông tin (information hiding) và quản lí sự phụ thuộc mã nguồn (dependency management). Các đoạn mã sau đây có thể chưa hoàn toàn chính xác về mặt cú pháp, chúng được dùng để minh họa cho các kĩ thuật thiết kế mà thôi.
1- Nested class là gì? Tại sao chúng ta cần nested class?
Nested class là một class được “viết” (enclosed) bên trong phạm vi (scope) của một class khác.
// Ví dụ 1: Nested class
//
class OuterClass
{
class NestedClass
{
// ...
};
// ...
};
Trong đoạn mã trên, NestedClass là một nested class được “viết” bên trong class OuterClass. Các nested class rất hữu ích cho việc tổ chức mã nguồn, quản lí quyền truy nhập (access) và các phụ thuộc (dependencies). Các nested class tuân theo các quy tắc thông thường về quyền truy nhập giống như các dữ liệu thành phần và các hàm thành phần. Tức là, nếu NestedClass được khai báo là public thì chúng ta có thể sử dụng nó từ bất cứ đâu thông qua tên gọi OuterClass::NestedClass. Ngược lại, nếu NestedClass được khai báo là private thì chỉ có các thành phần và các hàm bạn (friends) của OuterClass là có quyền truy nhập đến nó. Thông thường, các nested class chứa các cài đặt riêng cho OuterClass, do đó thường được khai báo là private.
Chú ý rằng nested class khác với namespace. Các namespace chỉ thuần túy nhóm các tên lại với nhau chứ không mang lại khả năng quản lí quyền truy nhập. Nếu bạn muốn quản lí quyền truy nhập tới một lớp, một trong các giải pháp là viết nó thành nested class trong một class khác.
2- Local class là gì? Tại sao chúng ta cần các local class?
Local class là một class được định nghĩa bên trong một hàm thông thường hoặc một hàm thành phần (member function). Trong ví dụ sau đây, LocalClass là một local class được định nghĩa bên trong một hàm thông thường có tên là f.
// Ví dụ 2: Local class
//
int f()
{
class LocalClass
{
// ...
};
// ...
};
Giống như nested class, local class là một công cụ hữu ích phục vụ việc quản lí những sự phụ thuộc về mã nguồn (code dependencies). Trong ví dụ 2, chỉ có đoạn mã trong thân hàm f mới được phép sử dụng LocalClass. LocalClass thường chứa những cài đặt riêng cho hàm f nên không cần thiết phải có khả năng truy nhập được từ bên ngoài.
Bạn có thể sử dụng local class gần như trong mọi tình huống có thể sử dụng class thông thường. Một ngoại lệ quan trọng cần ghi nhớ là: Các local class không thể đóng vai trò tham số kiểu (template parameter). Ví dụ dưới đây trích từ tài liệu chuẩn C++:
A local type, a type with no linkage, an unnamed
type or a type compounded from any of these types
shall not be used as a template-argument for a
template type-parameter. [Example:
template
class X { /* ... */ };
void f()
{
struct S { /* ... */ };
X x3; // error: local type used as
// template-argument
X x4; // error: pointer to local type
// used as template-argument
}
-end example]
Tóm lại, cả nested class lẫn local class đều là những công cụ hữu ích của C++ dùng để ẩn thông tin và quản lí quyền truy nhập và các phụ thuộc.
Nested Funtion
Một vài ngôn ngữ (không phải C++) cho phép chúng ta viết các nested function. Giống như các nested class, nested function là một function được viết bên trong một function khác. Những đặc điểm quan trọng của nested function là:
- Các nested function có quyền truy nhập đến các biến cục bộ của hàm chứa nó.
- Các nested function là “cục bộ”, nghĩa là không thể truy nhập tới chúng từ bên ngoài, trừ khi có một con trỏ trỏ đến nested function được cung cấp bởi hàm chứa.
Nếu như các nested class hữu ích bởi chúng cho phép điều kiển sự “ẩn hiện” (visibility) của một lớp thì các nested function hữu ích bởi chúng cho phép điều khiển sự “ẩn hiện” của một hàm.
Trả lời cho câu hỏi 3: Các giải pháp sử dụng class để mô phỏng nested function trong C++
Chú ý: “mô phỏng” ở đây được hiểu theo nghĩa là: Xây dựng một class g bên trong một hàm f, sao cho f có thể sử dụng g như một nested function
void f()
{
class g { … }; g();
}
Nói đến một class được sử dụng như một function, chúng ta nghĩ ngay đến các function object. Giải pháp đầu tiên mà hầu hết mọi người sẽ đưa ra là:
POSIX Thread (7) – Condition Variables
Chúng ta đã biết cách thức dùng mutex để đồng bộ hóa giữa các thread, tránh xung đột giữa các thread khi cùng truy cập tài nguyên. Tuy nhiên thì không phải mutex làm được tất cả. Ví dụ như chúng ta sẽ làm thế nào nếu chúng ta muốn thread đợi một điều kiện nào đó xảy ra với dữ liệu trong vùng chia sẻ? Chắc chắn là chúng ta sẽ làm bằng cách lặp liên tục việc khóa và mở khóa mutex (để đảm bảo đồng bộ giữa các thread cùng truy nhập vào vùng dữ liệu chia sẻ) và kiểm tra bất cứ sự thay đổi nào trên dữ liệu. Cùng lúc đó sẽ rất nhanh chóng thread sẽ mở khóa mutex cho các thread khác có thể thực hiện sự thay đổi trên vùng dữ liệu đó. Như vậy thì cách tiếp cận này thật kinh khủng bởi vì chúng ta sẽ cần một vòng lặp busy-loop để nhận ra sự thay đổi ở vùng dữ liệu. Nó thật là “lãng phí CPU”. (Bạn cần phải phân biệt giữa một chương trình ở trạng thái idle và busy!!!).
Chúng ta có thể để cho thread “ngủ” một chút, ví dụ 3 giây chẳng hạn ở giữa mỗi một lần kiểm tra, nhưng rõ ràng nó không tối ưu tuyệt đối. Cái chúng ta cần là phải đưa thread đó vào trạng thái ngủ cho đến khi một “điều kiện” nào đó được thỏa mãn. Một khi điều kiện được thỏa mãn thì nó sẽ đánh thức thread của chúng ta để nó tiếp tục sử lý. Đó chính là một kiểu cơ chế báo hiệu (signal). Khi có tín hiệu thì thread mới được đánh thức để sử lý tín hiệu đó.
Trong bài này chúng ta sẽ sử dụng biến pthread_condition_t để thể hiện cách thức báo hiệu này. Biến pthread_condition_t có cách sử dụng cũng tương tự như biến mutex. Chúng ta khai báo và khởi tạo như sau:
[Java] Pass-by-value or Pass-by-reference?
Một trong những điểm khó khăn (và gây tranh cãi) cho những lập trình viên C++ khi lập trình Java là việc pass-by-value hay pass-by-reference. Ví dụ:
Object a = new Object("Object A"); //kỳ quặc với C++: Object* a = new ...
Object b = a;
b.setNewName("Object B");
Theo cách hiểu của C++ devs thì rõ ràng Object b thay đổi tên chẳng liên quan gì đến Object a cả. Thực tế theo Java thì khác, Object a sẽ có name là “Object B” chẳng khác gì Object b cả.
Để Object b hoàn toàn “độc lập” với Object a thì:
Object b = a.clone();
Thế nhưng hàm swap() trong Java lại chẳng hoạt động theo cách pass-by-reference.
private void swap(Type arg1, Type arg2) {
Type temp = arg1;
arg1 = arg2;
arg2 = temp;
}
Vậy đấy!!! Java thực sự đã làm như thế nào? Ẩn sau những cái lằng nhằng gây tranh cãi như vậy là gì?