Lệnh sed: thay thế chuỗi, xóa dòng và cách dùng tùy chọn -i

Môi trường thử nghiệmHọ RHELAlmaLinux 9.8Tài khoản rootKiểm tra ngày 2026-10-28

Lệnh sed là công cụ Linux đọc tệp từng dòng và thực hiện thay thế, xóa, chèn, nhờ đó bạn có thể sửa giá trị trong tệp cấu hình mà không cần mở trình soạn thảo. Khi chạy sed trên bản sao wp-config.php của WordPress ở máy chủ AlmaLinux 9, chúng tôi đã đổi được tên cơ sở dữ liệu mà vẫn giữ tệp gốc nhờ -i.bak.

Các thông báo lỗi trong bài này được giữ nguyên như khi in ra dưới locale tiếng Anh.

1️⃣ Cách dùng cơ bản của lệnh sed và thay thế bằng s

Lệnh s, được dùng nhiều nhất, thay thế chuỗi theo dạng [s/chuỗi cần tìm/chuỗi mới/]. Lệnh chỉ thay kết quả đầu tiên tìm thấy trên một dòng.

echo 'http://example.com http://example.com/blog' | sed 's/http:/https:/'
https://example.com http://example.com/blog

Để thay mọi kết quả trên dòng, hãy thêm cờ g vào cuối.

echo 'http://example.com http://example.com/blog' | sed 's/http:/https:/g'
https://example.com https://example.com/blog

Nếu thêm tên tệp vào cuối, sed đọc tệp đó và in kết quả đã thay. Trên bản sao wp-config-sample.php của WordPress đặt tên wp-config.php, chúng tôi đổi giá trị DB_USER và chỉ kiểm tra dòng đó bằng grep.

sed 's/username_here/wp_user/' wp-config.php | grep DB_USER
define( 'DB_USER', 'wp_user' );

Vì giá trị trong đầu ra đã đổi nên dễ tưởng tệp cũng đổi, nhưng khi chạy không có tùy chọn, sed chỉ in kết quả ra màn hình và giữ nguyên tệp gốc. Khi tìm lại cùng dòng đó trong tệp, giá trị ban đầu vẫn còn.

grep DB_USER wp-config.php
define( 'DB_USER', 'username_here' );

Để đổi cả tệp gốc, hãy dùng tùy chọn -i ở mục 4️⃣.

2️⃣ Chọn dòng trong sed theo số dòng và mẫu (-n, p)

Không có địa chỉ, lệnh s áp dụng cho mọi dòng, nên để chỉ xử lý một số dòng, hãy viết số dòng hoặc mẫu làm địa chỉ trước lệnh. -n tắt tự động in và p in các dòng đã chọn. Dùng cùng nhau thì chỉ hiện dòng 23.

sed -n '23p' wp-config.php
define( 'DB_NAME', 'database_name_here' );

Nối hai số dòng bằng dấu phẩy sẽ hiện khoảng đó. Dòng 23 đến 32 là phần chứa thiết lập tên cơ sở dữ liệu, người dùng, mật khẩu và máy chủ.

sed -n '23,32p' wp-config.php
define( 'DB_NAME', 'database_name_here' );

/** Database username */
define( 'DB_USER', 'username_here' );

/** Database password */
define( 'DB_PASSWORD', 'password_here' );

/** Database hostname */
define( 'DB_HOST', 'localhost' );

Nếu viết mẫu giữa các dấu gạch chéo thay cho số dòng, mọi dòng chứa mẫu đó đều được chọn.

sed -n '/DB_/p' wp-config.php
define( 'DB_NAME', 'database_name_here' );
define( 'DB_USER', 'username_here' );
define( 'DB_PASSWORD', 'password_here' );
define( 'DB_HOST', 'localhost' );
define( 'DB_CHARSET', 'utf8mb4' );
define( 'DB_COLLATE', '' );

Lệnh [=] in số của dòng đã chọn. Địa chỉ $ nghĩa là dòng cuối, nên [$=] cho biết tổng số dòng của tệp.

sed -n '/DB_HOST/=' wp-config.php
32
sed -n '$=' wp-config.php
102

Địa chỉ cũng có thể đặt trước lệnh s. Bên dưới là kết quả chỉ đổi localhost ở dòng 32 và chỉ in dòng đã đổi bằng cờ p.

sed -n '32s/localhost/127.0.0.1/p' wp-config.php
define( 'DB_HOST', '127.0.0.1' );

Khi chạy p không có -n, dòng đã chọn hiện thêm một lần. sed đọc từng dòng vào pattern space, chạy lệnh rồi tự động in pattern space, nên dòng 2 đã được p in sẽ xuất hiện lại qua tự động in.

sed '2p' wp-config.php | head -n 4
<?php
/**
/**
 * The base configuration for WordPress

Cách đọc và xử lý từng dòng này giống băng chuyền nhà máy đặt từng linh kiện lên bàn làm việc, gia công rồi chuyển sang linh kiện tiếp theo.

Bạn có thể so sánh lần lượt trong sơ đồ bên dưới xem mỗi lệnh in gì trên từng dòng.

🧭 Pattern space của sed và tự động in: p, d ở dòng 2
Sơ đồ giải thích
⚙️ Lệnh
$ sed '2p'-n '2p''2d' wp-config.php
Dòng đã đọcChạy lệnh và đầu ra
Dòng 1 → pattern space<?php
➜
Khác địa chỉ 2: không có lệnhTự động in 1 lầnKhông có đầu ra do -n
Dòng 2 → pattern space/**
➜
Trùng địa chỉ 2: chạy pTrùng địa chỉ 2: chạy dp 1 lần + tự động 1 lầnChỉ in 1 lần bằng pXóa pattern space rồi sang dòng tiếp theo
Dòng 3 → pattern space * The base configuration for WordPress
➜
Khác địa chỉ 2: không có lệnhTự động in 1 lầnKhông có đầu ra do -n
🖥️ Những gì hiện trên màn hình (dòng 1~3)
<?php/**/** * The base configuration for WordPress
p in pattern space thêm một lần, nên không có -n thì dòng 2 được in hai lần.
-n tắt tự động in, nên chỉ dòng 2 được chọn bằng p được in một lần.
d xóa pattern space rồi sang dòng tiếp theo, nên dòng 2 không được tự động in.

3️⃣ Xóa và chèn dòng bằng lệnh sed (d, i, a)

d xóa các dòng đã chọn. Để xem mẫu cấu hình nginx bên dưới mà không có dòng chú thích, hãy chọn các dòng bắt đầu bằng # hoặc chỉ có khoảng trắng trước # bằng mẫu [^ *#].

cat example.conf
# example.com
server {
    listen 80;
    server_name example.com www.example.com;

    # document root
    root /var/www/example.com;
    index index.php index.html;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }
}
sed '/^ *#/d' example.conf
server {
    listen 80;
    server_name example.com www.example.com;

    root /var/www/example.com;
    index index.php index.html;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }
}

Nối lệnh bằng dấu chấm phẩy sẽ xóa luôn [^$], nghĩa là dòng trống. Hai dòng trống còn lại sau khi xóa chú thích biến mất, chỉ còn các dòng cấu hình.

sed '/^ *#/d; /^$/d' example.conf
server {
    listen 80;
    server_name example.com www.example.com;
    root /var/www/example.com;
    index index.php index.html;
    location / {
        try_files $uri $uri/ /index.php?$args;
    }
}

i chèn chữ vào trước dòng đã chọn, a chèn vào sau dòng đã chọn. Kết quả chèn một dòng chú thích trước dòng 1 như bên dưới.

sed '1i # managed by sed' example.conf | head -n 3
# managed by sed
# example.com
server {

Dễ tưởng rằng chữ thụt lề sau a sẽ giữ cả thụt lề, nhưng GNU sed bỏ qua khoảng trắng ngay sau a và chỉ chèn chữ.

sed '/index index.php/a    client_max_body_size 64M;' example.conf
# example.com
server {
    listen 80;
    server_name example.com www.example.com;

    # document root
    root /var/www/example.com;
    index index.php index.html;
client_max_body_size 64M;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }
}

Để giữ thụt lề, hãy thêm dấu gạch chéo ngược sau a. Từ khoảng trắng sau dấu gạch chéo ngược trở đi đều được đưa vào như chữ.

sed '/index index.php/a\    client_max_body_size 64M;' example.conf
# example.com
server {
    listen 80;
    server_name example.com www.example.com;

    # document root
    root /var/www/example.com;
    index index.php index.html;
    client_max_body_size 64M;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }
}

c thay toàn bộ dòng đã chọn. Bên dưới là bốn dòng đầu của kết quả đổi dòng listen 80 thành 8080.

sed '/listen 80;/c\    listen 8080;' example.conf | head -n 4
# example.com
server {
    listen 8080;
    server_name example.com www.example.com;

4️⃣ Sửa trực tiếp tệp bằng sed -i và tên tệp sao lưu

-i lưu kết quả vào tệp gốc thay vì in ra màn hình. Chữ viết liền ngay sau -i được thêm vào cuối tên tệp sao lưu. wp-config.php và các tệp khác mà trang web đọc nên được sửa bằng -i.bak để giữ lại tệp gốc.

cp wp-config-sample.php wp-config.php
sed -i.bak 's/database_name_here/wordpress_db/' wp-config.php

Chạy với -i thì màn hình không hiện gì, nên hãy kiểm tra tệp bằng ls -l.

ls -l wp-config.php*
-rw-r--r-- 1 root root 3333 Oct 28 15:13 wp-config.php
-rw-r--r-- 1 root root 3339 Oct 28 15:13 wp-config.php.bak

Tệp đã sửa và tệp .bak nằm cạnh nhau. Kích thước giảm 6 byte vì database_name_here được đổi thành wordpress_db ngắn hơn. So sánh hai tệp bằng diff sẽ chỉ thấy dòng đã đổi.

diff wp-config.php.bak wp-config.php
23c23
< define( 'DB_NAME', 'database_name_here' );
---
> define( 'DB_NAME', 'wordpress_db' );

Dòng đã đổi là một dòng DB_NAME ở dòng 23.

Nếu có nhiều giá trị cần đổi, hãy nối các script bằng -e và chạy một lượt.

sed -i -e 's/username_here/wp_user/' -e 's/password_here/wp_pass/' wp-config.php
grep -n -e DB_USER -e DB_PASSWORD wp-config.php
26:define( 'DB_USER', 'wp_user' );
29:define( 'DB_PASSWORD', 'wp_pass' );

Nếu viết liền -i và -e thành [-ie], e bị đọc thành một phần tên sao lưu, và tệp wp-config.phpe xuất hiện như bên dưới.

sed -ie 's/127.0.0.1/localhost/' wp-config.php
ls wp-config.php*
wp-config.php
wp-config.php.bak
wp-config.phpe

-i ghi nội dung đã sửa vào tệp mới rồi đổi sang tên gốc, nên số inode của tệp khác nhau trước và sau khi chạy.

ls -i wp-config.php
207618887 wp-config.php
sed -i 's/localhost/127.0.0.1/' wp-config.php
ls -i wp-config.php
207618883 wp-config.php

Số inode từ 207618887 trước khi chạy đã đổi thành 207618883.

Nếu tệp không tồn tại hoặc thiếu tên tệp, sed kết thúc với lỗi bên dưới và không tệp nào bị đổi.

sed -i 's/x/y/' no-such.php
sed: can't read no-such.php: No such file or directory
sed -i 's/x/y/'
sed: no input files

5️⃣ Biểu thức chính quy của sed, đổi dấu phân cách và tùy chọn

🔲 Biểu thức chính quy và đổi dấu phân cách

Khi đổi giá trị chứa dấu gạch chéo như đường dẫn, dấu phân cách của lệnh s lẫn với dấu gạch chéo trong giá trị, nên mỗi dấu gạch chéo trong giá trị cần một dấu gạch chéo ngược.

sed -n 's/\/var\/www\/example.com/\/srv\/www\/example.com/p' example.conf
    root /srv/www/example.com;

Ký tự ngay sau s trở thành dấu phân cách, nên đổi sang | vốn không có trong giá trị sẽ cho cùng kết quả mà không cần dấu gạch chéo ngược.

sed -n 's|/var/www/example.com|/srv/www/example.com|p' example.conf
    root /srv/www/example.com;

Dấu chấm (.) trong mẫu khớp với một ký tự bất kỳ. Bên dưới là kết quả mẫu tìm example.com đã đổi cả exampleXcom.

echo 'exampleXcom example.com' | sed 's/example.com/test.org/g'
test.org test.org

Để tìm dấu chấm đúng nghĩa, hãy đặt dấu gạch chéo ngược phía trước.

echo 'exampleXcom example.com' | sed 's/example\.com/test.org/g'
exampleXcom test.org

Phần trong ngoặc được gọi lại trong chuỗi mới bằng [\1]. Với -E, ngoặc và + dùng được mà không cần dấu gạch chéo ngược. Bên dưới là kết quả giữ nguyên số sau listen và thêm default_server.

sed -nE 's/listen ([0-9]+);/listen \1 default_server;/p' example.conf
    listen 80 default_server;

Chạy cùng script mà không có -E thì ngoặc bị đọc thành chữ, và xuất hiện lỗi không có nhóm để gọi lại. Để dùng không có -E, hãy thêm dấu gạch chéo ngược cho ngoặc và +.

sed -n 's/listen ([0-9]+);/listen \1 default_server;/p' example.conf
sed: -e expression #1, char 46: invalid reference \1 on `s' command's RHS
sed -n 's/listen \([0-9]\+\);/listen \1 default_server;/p' example.conf
    listen 80 default_server;

[&] trong chuỗi mới nghĩa là toàn bộ chữ khớp với mẫu, nên bạn có thể thêm # trước phần khớp để biến dòng đó thành chú thích.

sed -n 's/server_name .*;/# &/p' example.conf
    # server_name example.com www.example.com;

🔲 Tùy chọn của lệnh sed

📌 Tùy chọn chính: kết quả chạy trong bài này

Tùy chọnChức năngKết quả trong bài này
-nTắt tự động in và chỉ in các dòng được chọn bằng psed -n '23p' chỉ hiện dòng 23; không có -n thì 2p in dòng 2 hai lần
-iLưu kết quả vào tệp gốc thay vì màn hình (chữ ngay sau được thêm vào cuối tên sao lưu)-i.bak tạo wp-config.php.bak; số inode đổi sau khi chạy
-eNối nhiều script và chạy một lượtDB_USER và DB_PASSWORD đổi cùng lúc; viết liền thành -ie sẽ tạo bản sao lưu wp-config.phpe
-EDùng biểu thức chính quy mở rộng (không cần dấu gạch chéo ngược cho ngoặc và +)In listen 80 default_server;; cùng script không có -E báo lỗi [invalid reference]
--follow-symlinksCùng với -i, sửa tệp gốc mà liên kết trỏ tớiKhông có thì tệp thường thay chỗ liên kết và tệp gốc giữ nguyên; có thì giá trị gốc đổi

📎 Tùy chọn khác: theo tài liệu hướng dẫn chính thức

Tùy chọnChức năng
-fĐọc script từ tệp rồi chạy
-rBiểu thức chính quy mở rộng, giống -E (-E khả chuyển hơn)
-sXử lý từng tệp riêng thay vì một luồng nối liền
-zChia dòng bằng ký tự null thay vì xuống dòng
-uĐọc đầu vào từng ít một và đẩy đầu ra thường xuyên hơn
--posixTắt mọi phần mở rộng GNU
--debugIn quá trình chạy ở dạng chi tiết

🔲 Trình mô phỏng lệnh sed

Thư mục làm việc của trình mô phỏng bên dưới có bản sao wp-config.php và example.conf. Bạn có thể tự nhập các lệnh đã học và kiểm tra tệp bị -i đổi bằng ls -l và diff.

Trình mô phỏng lệnh sedGNU sed
[root@server work]#
Dùng phím ↑↓ trên bàn phím để gọi lại các lệnh đã gõ trước đó.

🔢 FAQ & nội dung đề xuất

wp-config-sample.php của WordPress kết thúc dòng bằng CRLF, nên ngay trước cuối dòng có [\r] không nhìn thấy. [/false );$/] không in dòng nào, còn trên bản sao đã xóa [\r] bằng [s/\r$//], cùng mẫu đó đã tìm thấy dòng WP_DEBUG.

-i tạo tệp thường mới thay chỗ liên kết và lưu ở đó, nên tệp gốc mà liên kết trỏ tới không đổi. Để sửa tệp gốc, hãy chỉ định thêm [--follow-symlinks]. Khi đó liên kết vẫn còn và giá trị gốc đổi.

Ngay cả biến đặt bằng NEW=wp_user, nếu viết trong dấu nháy đơn thì shell không thay thế, và [$NEW] được đưa vào nguyên chữ. Khi bọc script bằng dấu nháy kép, shell thay biến trước và wp_user vào vị trí [$NEW].

🧭 Nội dung đề xuất về lệnh văn bản 9 bài viết · 2 tham khảo
🗂️ Lệnh xem · chỉnh sửa văn bản
📄 Lệnh grep 📄 Lệnh sort 📄 Lệnh uniq 📄 Lệnh tee 📄 Lệnh sed
📄 Lệnh cat 📄 Lệnh less 📄 Lệnh head · tail 📄 Lệnh vi · vim

ℹ️ Thông báo tiếp thị liên kết
Nội dung trên trang này có chứa liên kết affiliate (tiếp thị liên kết). Khi khách truy cập mua sản phẩm hoặc dịch vụ qua các liên kết này, trang sẽ nhận hoa hồng từ bên bán. Trong quá trình đó, số tiền người mua phải trả (sẽ giảm khi có chương trình khuyến mãi ↓) không hề tăng lên. Giá, khuyến mãi và tình trạng hàng được đăng theo thời điểm viết bài và có thể khác với thực tế, vì vậy hãy kiểm tra lại lần cuối với bên bán trước khi mua. Việc chọn và đánh giá sản phẩm dựa trên tiêu chí riêng của trang; việc có nhận hoa hồng hay không không ảnh hưởng đến thứ tự giới thiệu hay nội dung đánh giá.

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *

Prove your humanity: 5   +   5   =