sed 指令:字串取代、刪除行與 -i 選項用法
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_USERdefine( 'DB_USER', 'wp_user' );輸出中的值變了,很容易以為檔案也變了,但 sed 不加選項時只把結果輸出到畫面,原始檔案維持不變。再到檔案中找同一行,最初的值仍然留著。
grep DB_USER wp-config.phpdefine( 'DB_USER', 'username_here' );要連原始檔案一起變更,請使用 4️⃣ 的 -i 選項。
2️⃣ sed 以行號和樣式選取行(-n、p)
s 命令不加位址時會套用到所有行,因此只想處理特定行,就在命令前面寫上行號或樣式作為位址。-n 關閉自動輸出,p 輸出選取的行。兩者一起使用時,只會出現第 23 行。
sed -n '23p' wp-config.phpdefine( 'DB_NAME', 'database_name_here' );用逗號連接兩個行號,就會出現該範圍。第 23 行到第 32 行是包含資料庫名稱、使用者、密碼和主機設定的區段。
sed -n '23,32p' wp-config.phpdefine( '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.phpdefine( '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.php32sed -n '$=' wp-config.php102位址也可以加在 s 命令前面。下面是只在第 32 行變更 localhost,並以 p 旗標只輸出變更行的結果。
sed -n '32s/localhost/127.0.0.1/p' wp-config.phpdefine( '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這種逐行讀取處理的方式,就像工廠輸送帶把零件一個個送上工作台加工後,再換下一個零件。
每個命令在各行輸出什麼,可在下面的圖表中依序比較。
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.confserver {
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.confserver {
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.phpsed -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.php23c23
< 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.phpgrep -n -e DB_USER -e DB_PASSWORD wp-config.php26: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.phpls wp-config.php*wp-config.php
wp-config.php.bak
wp-config.phpe-i 會把修改內容寫入新檔案後再換回原本的名稱,因此執行前後檔案的 inode 編號不同。
ls -i wp-config.php207618887 wp-config.phpsed -i 's/localhost/127.0.0.1/' wp-config.phpls -i wp-config.php207618883 wp-config.php執行前為 207618887 的 inode 編號變成了 207618883。
檔案不存在或漏寫檔案名稱時,會以下面的錯誤結束,任何檔案都不會變更。
sed -i 's/x/y/' no-such.phpsed: can't read no-such.php: No such file or directorysed -i 's/x/y/'sed: no input files5️⃣ 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.confsed: -e expression #1, char 46: invalid reference \1 on `s' command's RHSsed -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 變更的檔案。
🔢 FAQ & 推薦內容







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