sed 指令:字串取代、刪除行與 -i 選項用法

測試環境RHEL 系列AlmaLinux 9.8root 帳號2026-10-28 確認

sed 指令是逐行讀取檔案,並執行取代、刪除與插入的 Linux 工具,不必開啟編輯器就能修改設定檔的值。我們在 AlmaLinux 9 伺服器上對 WordPress 的 wp-config.php 副本執行 sed,結果能以 -i.bak 保留原檔並變更資料庫名稱。

文章中刊出的錯誤訊息,都是在英文 locale 下輸出的原始內容。

1️⃣ sed 指令基本用法與 s 取代

最常用的 s 命令以 [s/要尋找的字串/要取代的字串/] 格式取代字串。一行之中只取代第一個找到的項目。

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

要取代一行中的所有字串,就在結尾加上 g 旗標。

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

在後面加上檔案名稱,sed 就會讀取該檔案並輸出取代後的結果。我們把 WordPress 的 wp-config-sample.php 複製成 wp-config.php,在副本中變更 DB_USER 的值,再用 grep 只確認那一行。

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

輸出中的值變了,很容易以為檔案也變了,但 sed 不加選項時只把結果輸出到畫面,原始檔案維持不變。再到檔案中找同一行,最初的值仍然留著。

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

要連原始檔案一起變更,請使用 4️⃣ 的 -i 選項。

2️⃣ sed 以行號和樣式選取行(-n、p)

s 命令不加位址時會套用到所有行,因此只想處理特定行,就在命令前面寫上行號或樣式作為位址。-n 關閉自動輸出,p 輸出選取的行。兩者一起使用時,只會出現第 23 行。

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

用逗號連接兩個行號,就會出現該範圍。第 23 行到第 32 行是包含資料庫名稱、使用者、密碼和主機設定的區段。

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' );

在斜線之間寫樣式來代替行號,就會選取包含該樣式的所有行。

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', '' );

[=] 命令輸出選取行的行號。位址 $ 代表最後一行,因此可用 [$=] 確認檔案的總行數。

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

位址也可以加在 s 命令前面。下面是只在第 32 行變更 localhost,並以 p 旗標只輸出變更行的結果。

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

不加 -n 執行 p 時,選取的行又多出現一次。sed 把每一行逐一讀進 pattern space,執行命令後自動輸出 pattern space,因此 p 輸出過的第 2 行會因自動輸出再次出現。

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

這種逐行讀取處理的方式,就像工廠輸送帶把零件一個個送上工作台加工後,再換下一個零件。

每個命令在各行輸出什麼,可在下面的圖表中依序比較。

🧭 sed 的 pattern space 與自動輸出:第 2 行的 p、d
說明圖解
⚙️ 命令
$ sed '2p'-n '2p''2d' wp-config.php
讀取的行命令執行與輸出
第 1 行 → pattern space<?php
➜
與位址 2 不同:沒有命令自動輸出 1 次因 -n 沒有輸出
第 2 行 → pattern space/**
➜
與位址 2 相同:執行 p與位址 2 相同:執行 dp 1 次 + 自動輸出 1 次只由 p 輸出 1 次清除 pattern space,前往下一行
第 3 行 → pattern space * The base configuration for WordPress
➜
與位址 2 不同:沒有命令自動輸出 1 次因 -n 沒有輸出
🖥️ 畫面上輸出的內容(第 1~3 行)
<?php/**/** * The base configuration for WordPress
p 會再輸出一次 pattern space,因此不加 -n 時第 2 行輸出兩次。
-n 關閉自動輸出,因此只有 p 選取的第 2 行輸出一次。
d 清除 pattern space 並前往下一行,因此第 2 行不會自動輸出。

3️⃣ sed 指令刪除與插入行(d、i、a)

d 是刪除選取行的命令。要在下面的 nginx 設定範例中去掉註解行來看,就用 [^ *#] 樣式選取以 # 開頭,或 # 前面只有空格的行。

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;
    }
}

用分號連接命令,就會連代表空白行的 [^$] 一起刪除。刪除註解後留下的兩個空白行消失,只剩下設定行。

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 在選取行之前插入文字,a 在選取行之後插入文字。在第 1 行前插入一行註解的結果如下。

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

很容易以為在 a 後面寫縮排的文字,縮排也會一起插入,但 GNU sed 會略過 a 後面的空格,只插入文字。

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;
    }
}

要保留縮排,就在 a 後面加上反斜線。反斜線後的空格起都會以文字插入。

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 是把選取行整行替換的命令。下面是把 listen 80 那一行改成 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️⃣ sed -i 直接修改檔案與備份檔名

-i 是把結果存到原始檔案而不是畫面的選項。緊接在 -i 後面的文字會加在備份檔名的結尾。 wp-config.php這類網站會讀取的檔案,要用 -i.bak 保留原檔再修改。

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

以 -i 執行時畫面不會輸出任何內容,所以要用 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

修改過的檔案和 .bak 檔案一起產生了。database_name_here 縮短成 wordpress_db,大小因此少了 6 位元組。用 diff 比較兩個檔案,就能只確認變更的行。

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

變更的行是第 23 行的 DB_NAME 這一行。

有多個值要變更時,就用 -e 串接指令碼一次執行。

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' );

把 -i 和 -e 連寫成 [-ie] 時,e 也會被當成備份名稱讀取,如下所示產生了 wp-config.phpe 檔案。

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 會把修改內容寫入新檔案後再換回原本的名稱,因此執行前後檔案的 inode 編號不同。

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

執行前為 207618887 的 inode 編號變成了 207618883。

檔案不存在或漏寫檔案名稱時,會以下面的錯誤結束,任何檔案都不會變更。

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️⃣ sed 指令規則運算式、變更分隔符號與選項

🔲 規則運算式與變更分隔符號

變更路徑這類含斜線的值時,s 命令的分隔符號會和值中的斜線混在一起,因此值中的每個斜線都要加上反斜線。

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

緊接在 s 後面的字元就是分隔符號,改成值裡沒有的 | 後,不用反斜線也能得到相同結果。

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

樣式中的點(.)可比對任何一個字元。下面是尋找 example.com 的樣式連 exampleXcom 也變更的結果。

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

要照字面尋找點,就在前面加上反斜線。

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

以括號包住的部分,可在取代字串中用 [\1] 叫回。加上 -E 後,括號和 + 不需反斜線即可使用。下面是保留 listen 後的數字並加上 default_server 的結果。

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

不加 -E 執行相同指令碼時,括號會被當成文字,出現沒有可叫回群組的錯誤。不用 -E 時,要在括號和 + 前加上反斜線。

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;

取代字串中的 [&] 代表符合樣式的全部文字,因此可在符合部分前加上 #,把該行變成註解。

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

🔲 sed 指令選項

📌 主要選項:本文實際執行的結果

選項作用本文看到的結果
-n關閉自動輸出,只輸出 p 選取的行sed -n '23p' 只出現第 23 行,不加 -n 時 2p 讓第 2 行出現兩次
-i把結果存到原始檔案而不是畫面(緊接在後的文字會加在備份名稱結尾)-i.bak 產生 wp-config.php.bak,執行後 inode 編號改變
-e串接多個指令碼一次執行DB_USER 和 DB_PASSWORD 兩個值一次變更,連寫成 -ie 時會產生 wp-config.phpe 備份
-E使用延伸規則運算式(括號和 + 不需反斜線)輸出 listen 80 default_server;,不加 -E 的相同指令碼出現 [invalid reference] 錯誤
--follow-symlinks與 -i 一起使用,修改連結指向的原始檔案不加時連結位置會產生一般檔案,原始檔案不變;加上時原始值會變更

📎 其他選項:依官方手冊

選項作用
-f從檔案讀取指令碼並執行
-r與 -E 相同的延伸規則運算式(可攜性以 -E 為佳)
-s把多個檔案分開處理,而不是視為一個連續串流
-z以空字元而非換行分隔各行
-u每次讀取較少輸入,並更頻繁送出輸出
--posix關閉所有 GNU 擴充功能
--debug以展開形式輸出執行過程

🔲 sed 指令模擬器

下面模擬器的工作資料夾裡有 wp-config.php 副本和 example.conf。你可以親自輸入前面的指令,並用 ls -l 和 diff 確認被 -i 變更的檔案。

sed 指令模擬器GNU sed
[root@server work]#
用鍵盤 ↑↓ 鍵可叫出先前輸入過的指令。

🔢 FAQ & 推薦內容

WordPress 的 wp-config-sample.php 行尾是 CRLF,因此行尾前有看不見的 [\r]。[/false );$/] 沒有輸出任何一行,在用 [s/\r$//] 刪除 [\r] 的副本中,相同樣式則找到了 WP_DEBUG 那一行。

-i 會在連結位置新建一般檔案並儲存,因此連結原本指向的原始檔案沒有變更。要修改原始檔案,請同時指定 [--follow-symlinks]。這時連結維持不變,原始值則變更了。

即使是以 NEW=wp_user 設定的變數,寫在單引號內時 Shell 也不會展開,[$NEW] 會照字面放入。用雙引號包住指令碼時,Shell 先展開變數,wp_user 就放進 [$NEW] 的位置。

🧭 文字指令推薦內容 9 篇 · 2 份參考資料
🗂️ 文字檢視 · 編輯指令
📄 grep 指令 📄 sort 指令 📄 uniq 指令 📄 tee 指令 📄 sed 指令
📄 cat 指令 📄 less 指令 📄 head · tail 指令 📄 vi · vim 指令

ℹ️ 聯盟行銷說明
本站內容包含聯盟行銷連結。訪客透過這些連結購買商品或服務時,本站會從賣家獲得佣金。在這個過程中,購買者支付的金額(遇到活動折扣時金額會降低↓)並不會因此提高。刊登的價格、折扣與庫存資訊以撰寫當時為準,可能與實際情況不同,購買前請向賣家做最後確認。商品的挑選與評價依本站自訂的標準撰寫,是否支付佣金不會影響介紹順序或評價內容。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

Prove your humanity: 4   +   4   =