【Treeman】Linux

shell

shell

【jq】 linux json 查詢工具(查詢篇)

{
  "firstName": "John",
  "lastName": "Smith",
  "age": 25,
  "address": {
    "streetAddress": "21 2nd Street",
    "city": "New York",
    "state": "NY",
    "postalCode": "10021"
  },
  "phoneNumber": [
    {
      "type": "home",
      "number": "212 555-1234"
    },
    {
      "type": "fax",
      "number": "646 555-4567"
    }
  ],
  "gender": {
    "type": "male"
  }
}
[root@jylee-stres-stest250 tmp]# cat data.json | jq .age

25
[root@jylee-stres-stest250 tmp]# cat data.json | jq .address.city
"New York"
[root@jylee-stres-stest250 tmp]# cat data.json | jq .firstName
"John"

[root@jylee-stres-stest250 tmp]# cat data.json | jq -r .firstName
John
[root@jylee-stres-stest250 tmp]# cat data.json | jq .address.city
"New York"
# 取得電話陣列
[root@jylee-stres-stest250 tmp]# cat data.json | jq .phoneNumber
[
  {
    "type": "home",
    "number": "212 555-1234"
  },
  {
    "type": "fax",
    "number": "646 555-4567"
  }
]



#取得第一組電話
[root@jylee-stres-stest250 tmp]# cat data.json | jq .phoneNumber[0]
{
  "type": "home",
  "number": "212 555-1234"
}

#取得第一組電話( type + number )
[root@jylee-stres-stest250 tmp]#cat data.json | jq -r '.phoneNumber[0] | .type+","+.number'
home,212 555-1234

#取得所有type
[root@jylee-stres-stest250 tmp]# cat data.json | jq '.phoneNumber[] | .type'
"home"
"fax"
[root@jylee-stres-stest250 tmp]# cat data.json | jq '.phoneNumber | map(.type)' 
[
  "home",
  "fax"
]
[root@jylee-stres-stest250 tmp]# cat data.json | jq '.phoneNumber | map(.type) | join(",")' 
"home,fax"
[root@jylee-stres-stest250 tmp]# cat sample.json | jq -r '.phoneNumber[] | select(.type == "home") '
{
  "type": "home",
  "number": "212 555-1234"
}

[root@jylee-stres-stest250 tmp]# cat sample.json | jq -r '.phoneNumber[] | select(.type == "home") | .number'
212 555-1234
# 回傳物件
[root@jylee-stres-stest250 tmp]# echo '{"a":1, "ip":["10.10.10.1","10.10.10.2"], "c":3, "d":4}' | jq '{ip, d}'

{
  "ip": [
    "10.10.10.1",
    "10.10.10.2"
  ],
  "d": 4
}

# 回傳傳列
[root@jylee-stres-stest250 tmp]# echo '{"a":1, "ip":["10.10.10.1","10.10.10.2"], "c":3, "d":4}' | jq '[{ip, d}]'

[
  {
    "ip": [
      "10.10.10.1",
      "10.10.10.2"
    ],
    "d": 4
  }
]
# 綜合查詢
# @timestamp > 2025-08-20T16:, http_status 5開頭
jq -r 'select((.["@timestamp"] | startswith("2025-08-20T16:"))
              and ((.http_status // .status | tostring) | test("^5")))
       | [."@timestamp", (.http_status // .status | tostring), .request_uri] | @tsv' \
  access.log-20250821
  
2025-08-20T16:15:59+08:00	500	/search/searchShop.jsp?keyword=%E6%A5%B5%E8%87%B4%E9%A2%A8%E6%A0%BC%20%E7%9A%AE%E8%B3%AA%E5%AE%A4%E5%85%A7%E6%8B%96%E9%9E%8B
2025-08-20T16:15:59+08:00	500	/search/_next/static/css/ed87e7f553f8bcd9.css
2025-08-20T16:16:00+08:00	500	/search/searchShop.jsp?keyword=%E5%B9%B3%E6%9D%BF%E9%9B%BB%E8%85%A6
2025-08-20T16:16:00+08:00	500	/search/_next/static/chunks/393-eda0e0e00dcf367e.js
2025-08-20T16:16:00+08:00	500	/search/_next/static/media/momo-icon.42337f3f.ttf
2025-08-20T16:16:00+08:00	500	/search/_next/static/chunks/webpack-b9b83558616d5724.js
2025-08-20T16:16:00+08:00	500	/search/_next/static/chunks/main-app-553b0eca9bdb3ac5.js

jq_array_to_shell


data

{
  "values": [
        {
          "email": "user1@domain.com",
          "id": "USER1_ID"
        },{
          "email": "user2@domain.com",
          "id": "USER2_ID"
        }
	]
}

ss.sh

while IFS=',' read -r email id; do
  echo "$email"
  echo "$id"
done <<EOF
$(jq -r '.values[] | "\(.email),\(.id)"' data2.json)
EOF
[root@jylee-stres-stest250 tmp]# sh ss.sh
user1@domain.com
USER1_ID
user2@domain.com
USER2_ID

https://stedolan.github.io/jq/manual/#Invokingjq

 

 

 

shell

【jq】 linux json 查詢工具(修改篇)

[root@jylee-stres-stest250 tmp]# echo '{"a":{"b":0, "c":1}}' | jq .
{
  "a": {
    "b": 0,
    "c": 1
  }
}
[root@jylee-stres-stest250 tmp]# echo '{"a":{"b":0, "c":1}}' | jq 'setpath(["a","b"];1)'
#修改 a . b ; 0 => 1
{
  "a": {
    "b": 1,
    "c": 1
  }
}

#修改 多筆值用 | 分開
#修改 a . b ; 0 => 1,
# 修改 a . c ;1=> array( 1,2)
[root@jylee-stres-stest250 tmp]# echo '{"a":{"b":0, "c":1}}' | jq 'setpath(["a","b"];1) | setpath(["a","c"];[1,2])'
{
  "a": {
    "b": 1,
    "c": [
      1,
      2
    ]
  }
}
[root@jylee-stres-stest250 tmp]# echo '{"a":{"b":0, "c":1},"d": 111}' | jq .
{
  "a": {
    "b": 0,
    "c": 1
  },
  "d": 111
}

# 刪除d節點
[root@jylee-stres-stest250 tmp]# echo '{"a":{"b":0, "c":1},"d": 111}' | jq 'delpaths([["d"]])'
{
  "a": {
    "b": 0,
    "c": 1
  }
}

# 刪除d節點, a.b 節點
[root@jylee-stres-stest250 tmp]# echo '{"a":{"b":0, "c":1},"d": 111}' | jq 'delpaths([["d"],["a","b"]])'
{
  "a": {
    "c": 1
  }
}
shell

【jq】相關連結

shell

【Shell】【tip】 找出目前誰使用swap

who_use_swap.sh


#!/bin/bash
for p in /proc/[0-9]*; do
  pid=${p##*/}
  swap=$(awk '/VmSwap:/ {print $2}' $p/status 2>/dev/null)
  comm=$(tr -d '\0' < $p/comm 2>/dev/null)
  [ -n "$swap" ] && [ "$swap" -gt 0 ] && printf "%10s KiB  pid=%s  %s\n" "$swap" "$pid" "$comm"
done | sort -nr | head -20
[root@localhost shell]# bash who_use_swap.sh 
       508 KiB  pid=31107  java
       204 KiB  pid=16675  java
       136 KiB  pid=30500  sentry
       116 KiB  pid=14021  sentry
       104 KiB  pid=1040  containerd
        88 KiB  pid=30650  sentry
        72 KiB  pid=30508  sentry
        52 KiB  pid=29817  sentry
        52 KiB  pid=10666  dockerd
        44 KiB  pid=30521  sentry
        40 KiB  pid=30491  sentry
        40 KiB  pid=12964  sentry
        36 KiB  pid=338  sentry
        28 KiB  pid=30082  sentry
        24 KiB  pid=30615  sentry
        20 KiB  pid=322  sentry
        16 KiB  pid=32662  containerd-shim
        16 KiB  pid=31934  sentry
        16 KiB  pid=30911  sentry
        16 KiB  pid=26832  sentry
shell

【Shell】【tip】使用暫存表,更新crontab

 

#!/bin/bash
# $$ => pid,使暫存檔名不重複
tmp_file=/tmp/cron$$

# 利用trap 刪除暫存檔
#This installs a trap handler for exit (0) and signals 1 (SIGHUP), 3 (SIGQUIT) and 15 (SIGTERM) 
# that removes a file presumably storing a process ID.
#See man 3 signal for details about signals.
trap "rm -rf $tmp_file" 0 1 3 15


cat > $tmp_file << EOF 
*/10 * * * * echo "Hello World"
EOF

cat $tmp_file
cat $tmp_file | crontab

 

shell

【Shell】【tip】使用 echo 輸出排程時間到log

# 使用 echo 輸出排程時間到log 
# 測試輸出到 /tmp/crontab.log
0 8 * * *  echo "$(date '+\%Y-\%m-\%d \%H:\%M:\%S') - $(curl -s 'http://localhost:8080/api/schedule/sendSMS/sendDailySms' 
--form "date=$(date -d 'yesterday' +\%Y-\%m-\%d)" --form 'onlyCheckData=true')" 
>> /tmp/crontab_$(date '+\%Y-\%m').log
shell

【Shell】linux 下source、sh、bash、./執行指令碼的區別

linux 下source、sh、bash、./執行指令碼的區別 - IT閱讀 (itread01.com)

1、source命令用法:
  source  FileName
  作用:在當前bash環境下讀取並執行FileName中的命令。該filename檔案可以無"執行許可權"
  注:該命令通常用命令“.”來替代。
  如:source .bash_profile
    . .bash_profile兩者等效。
  source(或點)命令通常用於重新執行剛修改的初始化文件。
  source命令(從 C Shell 而來)是bash shell的內建命令。
  點命令,就是個點符號,(從Bourne Shell而來)。
  source的程式主體是bash,指令碼中的$0變數的值是bash,而且由於作用於當前bash環境,指令碼中set的變數將直接起效
 
2、 sh, bash的命令用法:
   sh/bash FileName
   作用:開啟一個子shell來讀取並執行FileName中命令。該filename檔案可以無"執行許可權"
   注:執行一個shell指令碼時會啟動另一個命令直譯器.
     每個shell指令碼有效地執行在父shell(parent shell)的一個子程序裡.
      這個父shell是指在一個控制終端或在一個xterm視窗中給你命令指示符的程序.
     shell指令碼也可以啟動他自已的子程序.
      這些子shell(即子程序)使指令碼並行地,有效率地地同時執行指令碼內的多個子任務.
  在ubuntu中sh只是bash的一個連結。
  由於是在子shell中執行,指令碼設定的變數不會影響當前shell。
 
3、./的命令用法:
   ./FileName
   作用:開啟一個子shell來讀取並執行FileName中命令。該filename檔案需要"執行許可權"
   注:執行一個shell指令碼時會啟動另一個命令直譯器.
     每個shell指令碼有效地執行在父shell(parent shell)的一個子程序裡.
      這個父shell是指在一個控制終端或在一個xterm視窗中給你命令指示符的程序.
     shell指令碼也可以啟動他自已的子程序.
      這些子shell(即子程序)使指令碼並行地,有效率地地同時執行指令碼內的多個子任務.
  由於是在子shell中執行,指令碼設定的變數不會影響當前shell。
exec和source都屬於bash內部命令(builtins  commands),在bash下輸入man exec或man source可以檢視所有的內部命令資訊。

bash  shell的命令分為兩類:外部命令和內部命令。外部命令是通過系統呼叫或獨立的程式實現的,如sed、awk等等。內部命令是由特殊的檔案格式(.def)所實現,如cd、history、exec等等。

在說明exe和source的區別之前,先說明一下fork的概念。

fork是linux的系統呼叫,用來建立子程序(child process)。子程序是父程序(parent  process)的一個副本,從父程序那裡獲得一定的資源分配以及繼承父程序的環境。子程序與父程序唯一不同的地方在於pid(process id)。

環境變數(傳給子程序的變數,遺傳性是本地變數和環境變數的根本區別)只能單向從父程序傳給子程序。不管子程序的環境變數如何變化,都不會影響父程序的環境變數。

shell script:

有兩種方法執行shell scripts,一種是新產生一個shell,然後執行相應的shell  scripts;一種是在當前shell下執行,不再啟用其他shell。
新產生一個shell然後再執行scripts的方法是在scripts檔案開頭加入以下語句
#!/bin/sh
一般的script檔案(.sh)即是這種用法。這種方法先啟用新的sub-shell(新的子程序),然後在其下執行命令。
另外一種方法就是上面說過的source命令,不再產生新的shell,而在當前shell下執行一切命令。

source:

source命令即點(.)命令。

在bash下輸入man source,找到source命令解釋處,可以看到解釋"Read and execute commands from  filename in the current shell environment and  ..."。從中可以知道,source命令是在當前程序中執行引數檔案中的各個命令,而不是另起子程序(或sub-shell)。

exec:

在bash下輸入man exec,找到exec命令解釋處,可以看到有"No new process is  created."這樣的解釋,這就是說exec命令不產生新的子程序。那麼exec與source的區別是什麼呢?

exec命令在執行時會把當前的shell  process關閉,然後換到後面的命令繼續執行。

* fork ( /directory/script.sh)
    fork是最普通的,  就是直接在腳本里面用/directory/script.sh來呼叫script.sh這個指令碼.執行的時候開一個sub-shell執行呼叫的指令碼,sub-shell執行的時候,  parent-shell還在。sub-shell執行完畢後返回parent-shell.  sub-shell從parent-shell繼承環境變數.但是sub-shell中的環境變數不會帶回parent-shell
* source  (source /directory/script.sh)
    與fork的區別是不新開一個sub-shell來執行被呼叫的指令碼,而是在同一個shell中執行. 所以被呼叫的指令碼中宣告的變數和環境變數,  都可以在主指令碼中得到和使用.
* exec (exec /directory/script.sh)
     exec與fork不同,不需要新開一個sub-shell來執行被呼叫的指令碼. 被呼叫的指令碼與父指令碼在同一個shell內執行。但是使用exec呼叫一個新指令碼以後,  父指令碼中exec行之後的內容就不會再執行了。這是exec和source的區別。

下面用一個例子來講解

1.sh

#!/bin/bash  

A=B  

echo "PID for 1.sh before exec/source/fork:$"  
export A  

echo "1.sh: \$A is $A"  

case $1 in  
        exec)  
                echo "using exec..."  
                exec ./2.sh ;;  
        source)  
                echo "using source..."  
                . ./2.sh ;;  
        *)  
                echo "using fork by default..."  
                ./2.sh ;;  
esac  

echo "PID for 1.sh after exec/source/fork:$"  
echo "1.sh: \$A is $A"  

2.sh  


#!/bin/bash  

echo "PID for 2.sh: $"  
echo "2.sh get \$A=$A from 1.sh"  

A=C  

export A  

echo "2.sh: \$A is $A"  
下面在命令列中去執行

./1.sh fork

image-1645383274668.png

可以看到,1.sh是在父程序中執行,2.sh是在子程序中執行的,父程序的PID是5344,而子程序的是5345,當子程序執行完畢後,控制權返回到父程序。同時,在子程序改變環境變數A的值不會影響到父程序。

./1.sh source

image-1645383287482.png

由結果可知,1.sh和2.sh都是在同一程序中執行的,PID為5367

./1.sh exec

image-1645383299760.png

可知,兩個指令碼都是在同一程序中執行,但是請注意,使用exec終止了原來的父程序,因此,可以看到

echo "PID for 1.sh after exec/source/fork:$"  

echo "1.sh: \$A is $A"  

這兩個命令沒有執行

由這個例子,便大致可瞭解它們的區別了

shell

【Shell】date 做 timestamp 格式轉換計算

要將日期與 timestamp 互相做格式轉換,只要使用 date 就可以達成,date 還可以順便做些日期的加減換算。

 

<來源>Linux 使用 date 做 timestamp 格式轉換計算 – Tsung's Blog (longwin.com.tw)

shell

【Shell】awk 取出特定欄位

所以要抓 access.log 倒數第二欄 和 第二欄,範例如下:

想要過濾掉其他欄位,主要就是把不要的欄位設定為「空」,再來印出 $0 就可以了~

cut 也可以達成:

 

shell

【Shell】取得pubic ip

#curl ifconfig.me; echo
175.99.111.111
shell

【shell】內建變數

$BASH_ENV  absolute path of startup file
$CDPATH  directories searched by cd
$FCEDIT  absolute path of history editor
$HISTCMD  the history number of the current command
$HISFILE  absolute path of history file
$HISTSIZE  number of remembered commands
$HOME  login directory
$IFS  token delimiters
$LINENO  current line number in shell script
$LINES  terminal height
$MAIL  absolute path of mailbox
$MAILCHECK  number of seconds to check mail
$OLDPWD  absolute path of previous directory
$OPTARG  option set by getopt
$OPTIND  option's ordinal position set by getopt
$OSTYPE  the OS on which bash is executing
$PATH  command search path
$PPID  process ID of parent
$PS1  primary prompt
$PS2  secondary prompt
$PWD  absolute path of current directory
$RANDOM  random integer
$REPLY  default variable for read
$SECONDS  number of seconds since shell started
$SHELL  absolute pathname of preferred shell
$TMOUT  seconds to log out after lack of use
$UID  user ID of the current user
$$  process ID of current shell
$?  exit status of most recent statement
$#  參數的數目
$*  代表所有參數
$!  PID of the most recently started backgroup job
shell

【Shell】動態呼叫awk自訂函數

*test.sh

#!/bin/bash
awkshell="/tmp/newdf.$$"
#awkshell="/tmp/newdf"
trap "rm -f $awkshell" exit

cat << EOF > $awkshell
function showunit(size){
        mb = size / 1024;
        gb = mb / 1024;
        if ( size < 1024 || substr(size,1,1) !~ "[0-9]" || substr(size,2,1) !~ "[0-9]" ){ return size }
        else if ( mb < 1 ){ return size"K" }
        else if ( gb < 1 ){ return (int(mb*100)/100)"M" }
        else { return (int(gb*100)/100)"G"} 
}
!/Filesystem/{
        size=showunit($1)
        print size
}
EOF

#echo $awkshell
#cat $awkshell
echo $1 | awk -f $awkshell

exit 0
[root]$ sh test.sh 6666
6.5M
[root]$ sh test.sh 66666
65.1M
[root]$ sh test.sh 666666666
635.78G

 

shell

【 Shell】【Tool】測試機器防火牆是否開通

https://medium.com/%E8%BC%95%E9%AC%86%E5%B0%8F%E5%93%81-pks%E8%88%87k8s%E7%9A%84%E9%BB%9E%E6%BB%B4/firewall-proxy-i-hate-you-5923c77266d5

#!/bin/bash
services=(
"gcr.io"
"checkpoint-api.hashicorp.com"
"storage.googleapis.com monitoring.googleapis.com"
"gkeconnect.googleapis.com"
"iam.googleapis.com"
"dl.google.com"
"gcr.io"
"googleusercontent.com"
"www.googleapis.com"
"accounts.google.com"
"cloudresourcemanager.googleapis.com"
"container.googleapis.com"
"gkeconnect.googleapis.com"
"gkehub.googleapis.com"
"iam.googleapis.com"
"iamcredentials.googleapis.com"
"logging.googleapis.com"
"monitoring.googleapis.com"
"oauth2.googleapis.com"
"securetoken.googleapis.com"
"servicecontrol.googleapis.com"
"serviceusage.googleapis.com"
"storage.googleapis.com"
"stackdriver.googleapis.com"
"sts.googleapis.com"
"checkpoint-api.hashicorp.com"
"releases.hashicorp.com"
"this-url-wont-work.comx"
)
for s in ${services[@]}; do
   nc -v -z -w 3 $s 443 &> /dev/null && echo "$s:443 Online" || echo "$s:443 Offline"
done

結果:

gcr.io:443 Online
checkpoint-api.hashicorp.com:443 Online
storage.googleapis.com:443 Online
monitoring.googleapis.com:443 Online
gkeconnect.googleapis.com:443 Online
iam.googleapis.com:443 Online
dl.google.com:443 Online
gcr.io:443 Online
googleusercontent.com:443 Offline
www.googleapis.com:443 Online
accounts.google.com:443 Online
cloudresourcemanager.googleapis.com:443 Online
container.googleapis.com:443 Online
gkeconnect.googleapis.com:443 Online
gkehub.googleapis.com:443 Online
iam.googleapis.com:443 Online
iamcredentials.googleapis.com:443 Online
logging.googleapis.com:443 Online
monitoring.googleapis.com:443 Online
oauth2.googleapis.com:443 Online
securetoken.googleapis.com:443 Online
servicecontrol.googleapis.com:443 Online
serviceusage.googleapis.com:443 Online
storage.googleapis.com:443 Online
stackdriver.googleapis.com:443 Online
sts.googleapis.com:443 Online
checkpoint-api.hashicorp.com:443 Online
releases.hashicorp.com:443 Online
this-url-wont-work.comx:443 Offline
shell

【Shell】【Tool】批次更新密碼

如果有許多使用者需要批次重設密碼並強制其在下次登入時更新,可以使用一個簡單的 Shell 腳本來自動化這個過程。假設你有一個包含所有目標使用者名稱的文字檔,例如 users.txt,可以按照以下步驟操作:

  1. 建立使用者清單

    在 users.txt 中列出所有需要重設密碼的使用者名稱,每行一個。例如:

    user1
    user2
    user3
    
  2. 編寫批次重設密碼的腳本

    建立一個 Shell 腳本,批次執行密碼重設並強制更新。例如,將以下內容儲存為 reset_password.sh

    #!/bin/bash
    
    # 檢查 users.txt 是否存在
    if [[ ! -f users.txt ]]; then
        echo "Error: users.txt not found!"
        exit 1
    fi
    
    # 循環讀取每一個使用者
    while IFS= read -r username; do
        # 跳過空行
        if [[ -z "$username" ]]; then
            continue
        fi
    
        # 設定預設密碼或隨機密碼
        new_password="DefaultPassword123" # 或使用 `new_password=$(openssl rand -base64 12)` 生成隨機密碼
        echo "重設 $username 的密碼為 $new_password"
    
        # 重設密碼
        echo "$username:$new_password" | sudo chpasswd
    
        # 強制下次登入時更改密碼
        sudo chage -d 0 "$username"
    
        echo "$username 的密碼已重設並強制更新"
    done < users.txt
    
  3. 執行腳本

    為腳本增加執行權限,然後執行:

    chmod +x reset_password.sh
    sudo ./reset_password.sh
    
  4. 檢查結果

    執行完成後,你可以再次使用 chage -l username 指令逐一檢查使用者的密碼到期設定,確認是否成功。

這樣便可批次重設多位使用者的密碼,並強制其在下次登入時更新密碼。

shell

【Shell】【Tip】列出環境變數網址解析dns

image-1747466952908.png

#!/bin/bash

export A_HOST="https://www.google.com/a/b"
export B_HOST="https://tw.yahoo.com/a?a=a&b=b"
export C_HOST="https://www.microsoft.com/zh-tw/#bb"

echo "列出所有環境變數並解析疑似網址的 IP:"
echo "========================================="

# 顯示目前 DNS server
# 嘗試從 systemd-resolved 的配置中找出真實 DNS
if command -v resolvectl >/dev/null 2>&1; then
  dns_servers=$(resolvectl status | grep 'DNS Servers' | head -n 1 | awk -F': ' '{print $2}')
#elif [ -f /run/systemd/resolve/resolv.conf ]; then
#  dns_servers=$(grep -E '^nameserver' /run/systemd/resolve/resolv.conf | awk '{print $2}')
else
  dns_servers=$(grep -E '^nameserver' /etc/resolv.conf | awk '{print $2}')
fi

echo "目前使用的 DNS server:$dns_servers"
echo "-----------------------------------------"

# 暫存解析過的域名,避免重複查詢
declare -A resolved

while IFS='=' read -r name value; do
  if [[ "$value" =~ ^https?://([^:/]+) ]]; then
    host="${BASH_REMATCH[1]}"
  elif [[ "$value" =~ ^([a-zA-Z0-9.-]+\.[a-zA-Z]{2,})$ ]]; then
    host="${BASH_REMATCH[1]}"
  else
    continue
  fi

  if [[ -n "$host" && -z "${resolved[$host]}" ]]; then
    ip=$(dig +short "$host" | grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -n 1)
    resolved["$host"]="$ip"
    echo "$name=$value"
    if [[ -z "$ip" ]]; then
      echo " ↳ $host → [無法解析]"
    else
      echo " ↳ $host → $ip"
    fi
    echo "-----------------------------------------"
  fi
done < <(env)

echo ""
echo "系統 /etc/hosts 內容(不含註解與空行):"
echo "========================================="
grep -vE '^\s*#|^\s*$' /etc/hosts

 

shell

【Shell】【Tool】call_api

call_api() {
  curl -fsS \
    --connect-timeout 2 \
    --max-time 5 \
    --retry 2 --retry-delay 1 \
    -w " [HTTP_CODE=%{http_code}]\n" \
    "$URL"
}

好的 👍 我來逐一說明 call_api() 這段裡面每個 curl 參數的作用,並且說明為什麼要加:

call_api() {
  curl -fsS \
    --connect-timeout 2 \
    --max-time 5 \
    --retry 2 --retry-delay 1 \
    -w " [HTTP_CODE=%{http_code}]\n" \
    "$URL"
}

 參數逐一解析

  1. -f / --fail

    • 作用:當 HTTP 狀態碼是 4xx / 5xx 時,不會把 HTML 錯誤頁輸出到 stdout,而是直接返回非零 exit code。

    • 好處:可以在 script 判斷「這次呼叫失敗」,而不是誤以為拿到一大串錯誤 HTML 也算成功。


  1. -s / --silent

    • 作用:靜默模式,不顯示下載進度條與錯誤訊息(錯誤還是會 exit code ≠ 0)。

    • 好處:避免 cron job 或 log 裡塞滿進度百分比。


  1. -S / --show-error

    • 作用:在 -s 靜默模式下,仍然把錯誤訊息(例如 DNS 解析失敗、timeout)顯示出來。

    • 好處:結合 -s 使用,可以安靜但又不失錯誤訊息。


  1. --connect-timeout 2

    • 作用:設定 TCP 連線的最大等待時間(單位:秒)。

    • 例子:如果 API 服務根本沒在聽 port 8082,curl 會在 2 秒 內放棄。


  1. --max-time 5

    • 作用:整個 request(連線、傳輸、讀取)的最長時間,超過就中斷。

    • 好處:避免 API 掛住時,curl 一直卡在那裡。


  1. --retry 2

    • 作用:遇到「暫時性錯誤」(像 DNS 解析失敗、timeout、connection reset by peer),會自動重試最多 2 次。

    • 預設只會 retry network-level 的錯誤,不會 retry 4xx/5xx。


  1. --retry-delay 1

    • 作用:每次 retry 前延遲 1 秒

    • 預設會 delay 1 秒,但這裡寫死確保一致。


  1. -w " [HTTP_CODE=%{http_code}]\n"

    • 作用:在 response 輸出結尾,附加 HTTP 狀態碼。

    • 例子:成功時會多一行 [HTTP_CODE=200]

    • 好處:log 裡可以直接看出 API 狀態。


  1. "$URL"

    • 作用:實際要請求的 URL。

    • 這裡設成變數,方便修改。


 總結

這樣組合的意圖就是:


 

【茶包射手】

【茶包射手】

version `GLIBCXX_3.4.20' not found 解决方法

https://www.jianshu.com/p/050b2b777b9d

 

【茶包射手】

【cron】沒有依排程執行

檢查服務

# systemctl status crond
● crond.service - Command Scheduler
   Loaded: loaded (/usr/lib/systemd/system/crond.service; enabled; vendor preset: enabled)
   Active: active (running) since Mon 2024-04-22 13:11:51 CST; 7min ago
 Main PID: 17677 (crond)
   CGroup: /system.slice/crond.service
           └─17677 /usr/sbin/crond -n

Apr 22 13:11:51 localhost.localdomain systemd[1]: Started Command Scheduler.
Apr 22 13:11:51 localhost.localdomain crond[17677]: (CRON) INFO (RANDOM_DELAY will be scaled with factor 74% if used.)
Apr 22 13:11:51 localhost.localdomain crond[17677]: (CRON) INFO (running with inotify support)
Apr 22 13:11:51 localhost.localdomain crond[17677]: (CRON) INFO (@reboot jobs will be run at computer's startup.)


# 如果是ubuntu服務是 cron

# 如果沒有起請將服務起來
#  systemctl start crond
# 設定開機自動起服務
#  systemctl enable crond

檢查log

# 檢查cron log
cat /var/log/cron

# 檢查sys log
grep CRON /var/log/messages

【網路相關】

【網路相關】

【Linux】【Ubuntu】如何修改 ip

以下提供在 Ubuntu 18.04 以後(netplan)Ubuntu 16.04 舊版(/etc/network/interfaces) 的常見修改方式,請依照你實際版本選擇。


1️⃣ 確認目前網路設定工具

Ubuntu 18.04 以後預設使用 Netplan

ls /etc/netplan/

若此資料夾存在 YAML 檔案(例如 00-installer-config.yaml),代表使用 Netplan。


2️⃣ Netplan 修改(Ubuntu 18.04+)


3️⃣ 傳統 /etc/network/interfaces(Ubuntu 16.04 或自行安裝 ifupdown)

  1. 編輯:

    sudo nano /etc/network/interfaces
    
  2. 範例:

    auto ens33
    iface ens33 inet static
        address 192.168.1.100
        netmask 255.255.255.0
        gateway 192.168.1.1
        dns-nameservers 8.8.8.8 8.8.4.4
    
  3. 套用:

    sudo systemctl restart networking
    

4️⃣ 臨時修改 IP(重開機後失效)

若只想暫時修改:

sudo ip addr add 192.168.1.100/24 dev ens33
sudo ip route add default via 192.168.1.1

5️⃣ 驗證設定

ip addr show
ip route
ping 8.8.8.8

小提醒

以上即可依版本與需求選擇永久或臨時的 Ubuntu IP 修改方式。


 如果出現警告畫面

image-1757918219117.png

從這張截圖可以看到兩類主要警告訊息:


1️⃣ 檔案權限過開 (Permissions are too open)

Permissions for /etc/netplan/00-installer-config.yaml are too open.
Netplan configuration should NOT be accessible by others.

原因
Netplan 要求設定檔必須只有 root 可以寫,否則 netplan apply 會拒絕。

解法
把檔案權限調整為 600 或 640,例如:

sudo chmod 600 /etc/netplan/00-installer-config.yaml
# 或若需要同群組讀取
sudo chmod 640 /etc/netplan/00-installer-config.yaml

再確認:

ls -l /etc/netplan/00-installer-config.yaml
# -rw------- 或 -rw-r----- 都可以

2️⃣ gateway4 已被棄用

'gateway4' has been deprecated, use default routes instead.

Ubuntu 22.04 之後 gateway4 舊語法建議改成 routes:default

修改範例
舊:

ethernets:
  ens33:
    dhcp4: no
    addresses: [192.168.1.100/24]
    gateway4: 192.168.1.1

新:

ethernets:
  ens33:
    dhcp4: no
    addresses: [192.168.1.100/24]
    routes:
      - to: default
        via: 192.168.1.1

3️⃣ 其他訊息

WARNING:root:Cannot call Open vSwitch: ovsdb-server.service is not running.

如果沒有使用 Open vSwitch 可以忽略;若有需要,就啟動服務:

sudo systemctl enable --now ovsdb-server

建議修正步驟總結

  1. 調整權限

    sudo chmod 600 /etc/netplan/00-installer-config.yaml
    
  2. 修改 YAML 把 gateway4 換成 routes

  3. 驗證語法:

    sudo netplan try
    

    沒問題後:

    sudo netplan apply
    

這樣就能消除「Permissions too open」與「gateway4 deprecated」兩個警告。

【Top】 效能監控工具

 

image-1684291907122.png

top - 16:12:13 up 42 days, 37 min, 6 users, load average: 1.66, 1.67, 2.39
Tasks: 255 total, 8 running, 247 sleeping, 0 stopped, 0 zombie
Cpu0 : 31.4%us, 51.5%sy, 0.0%ni, 10.0%id, 0.0%wa, 0.0%hi, 6.7%si, 0.3%st
Cpu1 : 89.0%us, 9.0%sy, 0.0%ni, 2.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Cpu2 : 31.4%us, 51.8%sy, 0.0%ni, 15.4%id, 0.0%wa, 0.0%hi, 1.3%si, 0.0%st
Cpu3 : 34.2%us, 52.5%sy, 0.0%ni, 7.6%id, 0.0%wa, 0.0%hi, 5.6%si, 0.0%st
Mem: 16269604k total, 15986032k used, 283572k free, 1069332k buffers
Swap: 4193272k total, 0k used, 4193272k free, 3629176k cached

Linux上的top命令是一個非常有用的工具,它可以顯示系統中正在運行的進程的詳細信息,包括CPU、記憶體、磁盤和網路使用情況。以下是一些使用top命令的基本說明:

1. 開啟top:在終端窗口中輸入`top`並按下Enter鍵,即可開啟top命令的監視模式。

2. 介面說明:top的介面由多個欄位組成,每個欄位提供了特定的系統信息。其中一些常見的欄位包括:

- PID:進程ID。
- USER:執行進程的使用者名稱。
- PR:進程的優先級。
- NI:進程的優先級數值。
- VIRT:進程使用的虛擬記憶體大小。
- RES:進程使用的實體記憶體大小。
- SHR:進程共享的記憶體大小。
- %CPU:進程使用的CPU百分比。
- %MEM:進程使用的記憶體百分比。
- TIME+:進程運行的總時間。
- COMMAND:進程的命令名稱。

3. 排序方式:預設情況下,top按照CPU使用百分比(%CPU)進行排序。你可以按下鍵盤上的`<`或`>`鍵來改變排序方式。例如,按下`<`鍵可以按照進程ID(PID)進行排序,按下`>`鍵可以按照記憶體使用百分比(%MEM)進行排序。

4. 刷新頻率:預設情況下,top每隔3秒刷新一次顯示的進程列表。你可以按下鍵盤上的`s`鍵來改變刷新頻率,然後輸入所需的秒數。

5. 執行命令:在top界面中,你可以執行一些特定的命令,例如:

- `k`:終止選中的進程。輸入進程的PID並按下Enter鍵,然後選擇終止原因。
- `r`:修改進程的優先級。輸入進程的PID並按下Enter鍵,然後輸入新的優先級數值。
- `1`:切換到全局(CPU)總覽模式。
- `h`:顯示top命令的幫助信息。

6. q :退出top


Help 說明

Z、B、E、e:全局設置:'Z' 切換彩色顯示;'B' 切換粗體顯示;'E' 或 'e' 調整總結/任務記憶體的刻度。

l、t、m:切換總結顯示:'l' 切換載入平均值;'t' 切換任務/ CPU 狀態;'m' 顯示記憶體信息。

0、1、2、3、I:切換顯示:'0' 切換顯示 0 值;'1/2/3' 切換 CPU 或 NUMA 节點視圖;'I' 切換到 Irix 模式。

f、F、X:欄位設置:'f'/'F' 添加/移除/調整/排序欄位;'X' 增加固定寬度。

L、&、<、>:定位操作:'L'/'&' 查找/重複查找;移動排序列:'<'/'>' 左移/右移。

R、H、V、J:切換設置:'R' 切換排序方式;'H' 切換線程顯示;'V' 切換樹狀視圖;'J' 切換數字對齊。

c、i、S、j:切換設置:'c' 切換命令名稱/命令行顯示;'i' 切換空閒時間顯示;'S' 切換時間顯示;'j' 切換字符串對齊。

x、y:切換突出顯示:'x' 切換排序欄位的突出顯示;'y' 切換運行的任務突出顯示。

z、b:切換設置:'z' 切換彩色/單色顯示;'b' 切換粗體/反轉顯示(僅在 'x' 或 'y' 選項下)。

u、U、o、O:過濾條件:'u'/'U' 過濾按有效/任意使用者;'o'/'O' 過濾其他條件。

n、#、^O:設定顯示的最大任務數量:'n'/'#' 設定最大顯示任務數;按下 Ctrl+'O' 顯示其他過濾條件。

C、...:切換滾動座標顯示:'up'、'down'、'left'、'right'、'home'、'end'

k、r:操作任務:'k' 終止任務;'r' 修改任務的優先級。

d 或 s:設定更新間隔。

W、Y:寫入配置文件 'W';檢查其他輸出 'Y'。


load average 負載平均

load average: 1.66, 1.67, 2.39
最近 1分鐘 / 5分鐘 / 15分鐘

單核cpu來看,load值大於1代表系統滿載,load值為0代表完全空閒,理想數字在0.7以下會比較好
如果是4核心則為0.7*4  = 2.8以下比較好

參考
https://www.itread01.com/content/1548662434.html


us: is meaning of "user CPU time"
sy: is meaning of "system CPU time"
ni: is meaning of" nice CPU time"
id: is meaning of "idle"
wa: is meaning of "iowait" 
hi:is meaning of "hardware irq"
si : is meaning of "software irq"
st : is meaning of "steal time


Top 排序

在Linux中,`top`命令可以用来查看系统的实时性能信息。默认情况下,`top`的显示界面按照CPU使用率降序排列进程。但是,你可以通过按键来改变排序方式。以下是一些常用的排序键:

1. **按CPU使用率排序:**
- 按下 `Shift + P`

2. **按内存使用率排序:**
- 按下 `Shift + M`

3. **按累计CPU使用率排序:**
- 按下 `t` 键,然后选择 `%CPU`

4. **按累计内存使用率排序:**
- 按下 `t` 键,然后选择 `%MEM`

5. **按PID(进程ID)排序:**
- 按下 `Shift + N`

6. **按进程名称排序:**
- 按下 `c` 键

7. **按照其他列排序:**
- 在`top`的显示界面中,你可以使用左右箭头键来选择不同的列,然后按下 `o` 键来选择要排序的列。

8. **切换升序/降序排序:**
- 在排序之后,你可以按下 `R` 键来切换排序的顺序(升序或降序)。

请注意,这些键仅在`top`运行时有效,按下相应的键后,`top`将根据你的选择重新排序并更新显示。如果你希望在`top`启动时就按照特定的排序方式显示,你可以使用`top`命令的一些参数,例如:

top -o %CPU # 按照 CPU 使用率降序排列
top -o %MEM # 按照内存使用率降序排列

这些是一些基本的排序操作,根据你的需求可以选择适合的排序方式。


 

🖥 CPU 使用率指標速查表

指標 全名 意義 判斷標準
us user 使用者態 CPU(應用程式運算時間) - 高代表程式在跑計算(正常)- 長期 80–90% 可能 CPU 算力不足
sy system 核心態 CPU(系統呼叫/驅動/中斷) - 偶爾 5–15% 正常- 長期 >30% 可能系統呼叫太頻繁或 driver 問題
id idle CPU 閒置時間 - 高表示 CPU 很空閒- 低(接近 0)表示 CPU 幾乎滿載
wa iowait CPU 在等 I/O(磁碟/網路) - 0–5% 正常- >20% 有 I/O 壓力- >50% 嚴重瓶頸,CPU 幾乎都在等磁碟/網路- 100% = 完全被 I/O 卡住

📊 看 top 的例子

%Cpu0 : 12.0 us,  7.0 sy,  0.0 ni,  0.0 id, 81.0 wa,  0.0 hi,  0.0 si,  0.0 st

解讀:


📌 判斷邏輯

  1. us 高 → 程式運算密集(算力不足)

  2. sy 高 → 核心忙,可能 driver、系統呼叫過多

  3. wa 高 → I/O 磁碟/網路瓶頸

  4. id 低 → CPU 幾乎被榨乾


✅ 快速結論


要不要我幫你再做一張 「CPU 狀態 → 問題來源 → 解決方法」的對照表,讓你排查更直觀?

 

 

【資安】強制登出使用者

使用who查詢在線使用者
pkill -kill -t {tty} 強制登出

image-1633573964383.png

【圖形介面】Linux安裝圖形介面

* 安裝圖形介面
```
yum groupinstall -y "GNOME Desktop"
```
|run level|<|h
|0|關機(``不可設為預設``)|
|6|重新開機(``不可設為預設``)|
|1|單人文字模式|
|2|多人模式文字(無網路)|
|3|多人模式文字(有網路)|
|4|客製化模式3|
|5|多人模式圖形(有網路)|
```
系統使用"targets"取代以前的"run-levels"。下列為主要的兩個設定值:
multi-user.target: 表示 runlevel 3
graphical.target: 表示 runlevel 5

檢查現在系統的預設target的指令:systemctl get-default
```
*查看現在啟動
```
[snowFlake@www ~]$ sudo systemctl get-default
multi-user.target
```
*設定圖形啟動
```
[snowFlake@www ~]$ sudo systemctl set-default
graphical.target
```
*忘記指令可以查看/etc/inittab 檔案
```
# cat /etc/inittab
# inittab is no longer used when using systemd.
#
# ADDING CONFIGURATION HERE WILL HAVE NO EFFECT ON YOUR SYSTEM.
#
# Ctrl-Alt-Delete is handled by /usr/lib/systemd/system/ctrl-alt-del.target
#
# systemd uses 'targets' instead of runlevels. By default, there are two main targets:
#
# multi-user.target: analogous to runlevel 3
# graphical.target: analogous to runlevel 5
#
# To view current default target, run:
# systemctl get-default
#
# To set a default target, run:
# systemctl set-default TARGET.target
#
```

【圖形介面】tiger vnc

安裝

yum install tigervnc-server -y

VNC 預設 port 為 5900,而 :1 代表一個虛擬桌面,所以連結這個虛擬桌面的 port 為 5901(5900 + 1)或 1

複製設定檔

cp /lib/systemd/system/vncserver@.service /etc/systemd/system/vncserver@:1.service

以下是用root 帳號,如果是一般使用者,可使用註解區塊(使用者jcky,把root註解)

[Unit]
Description=Remote desktop service (VNC)
After=syslog.target network.target

[Service]
Type=simple

# Clean any existing files in /tmp/.X11-unix environment
ExecStartPre=/bin/sh -c '/usr/bin/vncserver -kill %i > /dev/null 2>&1 || :'
ExecStop=/bin/sh -c '/usr/bin/vncserver -kill %i > /dev/null 2>&1 || :'

# 一般帳號
# #ExecStart=/usr/sbin/runuser -l jacky -c "/usr/bin/vncserver %i"
# #PIDFile=/home/jacky/.vnc/%H%i.pid
#
# root 帳號
ExecStart=/usr/sbin/runuser -l root -c "/usr/bin/vncserver %i -geometry 1280x1024"
PIDFile=/root/.vnc/%H%i.pid

[Install]
WantedBy=multi-user.target

設定VNC密碼

如果是一般使用者要先切換到該身分下

su jacky

設定vnc 密碼

vncpasswd

使用root 帳號

su -
systemctl daemon-reload

啟用服務,並設定開機自動執行

systemctl start vncserver@:1.service
systemctl enable vncserver@:1.service

可使用vnc

【Linux】帳號管理

新增/刪除帳號

# -u 自訂UID
# -g 加入某群組,可使用GID, 或是群組名
# -d 自定使用的家目錄
# -M 不建立家目錄
# -s 自訂shell
# 新增帳號(包含家目錄)
# centos
usradd 新帳號名稱
# ubuntu
adduser 新帳號名稱



# 刪除帳號(保留家目錄) 
userdel user1
# 刪除帳號(刪除家目錄) 
userdel -r user1


# 修改帳號
usermod [-LU][-c <備註>][-d <登入目錄>][-e <有效期限>] [-f <緩沖天數>][-g <群組>][-G <群組>][-l <帳號名稱>][-s ] [-u ][用戶帳號]
#-c<備註> 修改用戶帳號的備註文字。
#-d登入目錄> 修改用戶登入時的目錄。
#-e<有效期限> 修改帳號的有效期限。
#-f<緩沖天數> 修改在密碼過期後多少天即關閉該帳號。
#-g<群組> 修改用戶所屬的群組。
#-G<群組> 修改用戶所屬的附加群組。
#-l<帳號名稱> 修改用戶帳號名稱。
#-L 鎖定用戶密碼,使密碼無效。
#-s 修改用戶登入後所使用的shell。
#-u 修改用戶ID。
#-U 解除密碼鎖定。

# user1 加入 root 群組
usermod -aG root user1
# user1 移出 root 群組
gpasswd -d root user1

 

設定密碼過期

#chage:密碼失效是通過此命令來管理的。
#參數意思:
#-m 密碼可更改的最小天數。為零時代表任何時候都可以更改密碼。
#-M 密碼保持有效的最大天數。
#-W 用戶密碼到期前,提前收到警告信息的天數。
#-E 帳號到期的日期。過了這天,此帳號將不可用。
#-d 上一次更改的日期
#-i 停滯時期。如果一個密碼已過期這些天,那麽此帳號將不可用。
#-l 例出當前的設置。由非特權用戶來確定他們的密碼或帳號何時過期。

# 設定密碼過期時間0天(使用者登入需更改密碼)
sudo chage -d 0 使用者名稱
# 設定密碼永不過期
sudo chage -M -1 使用者名稱
# 設定帳號不會過期
sudo usermod -e '' 使用者名稱
# 設定帳號密碼都不會過期
sudo chage -M -1 -E -1 使用者名稱

禁止 root ssh 登入

# 修改/etc/ssh/sshd_config  
vim /etc/ssh/sshd_config  

# PermitRootLogin yes 
# 改為
PermitRootLogin no

# 重新啟動 ssh服務
systemctl restart sshd

群駔相關

# 新增群組
# groupadd [-g GID] 群組名
groupadd group1 

# 刪除群組
# groupdel群組名
groupdel group1

# 查詢使用者群組
# 方法一 groups 使用者
groups webmaster
########################/*
[root@test webmon]# groups  webmaster
webmaster : webmaster nginx
#########################*/
# 方法二 cat /etc/group
cat /etc/group | grep webmaster
########################/*
[root@webmon205 webmon]# cat /etc/group | grep webmaster
webmaster:x:1000:webmaster
nginx:x:979:webmaster
#########################*/

# 將使用者加入某群組
# ex.將user1加入ftp群組
usermod -a -G ftp user1
# ex.將user1移出ftp群組
gpasswd -d ftp app

# 修改主群組
# ex.將user1主群組改為nginx
usermod -g nginx user1

【Linux】記憶體相關

https://huenlil.pixnet.net/blog/post/26822270

釋放記憶體

echo 1 > /proc/sys/vm/drop_cache

釋放dentries、inodes所用的 cache memory

echo 2 > /proc/sys/vm/drop_caches

釋放pagecache、dentry、inode 所用的 cache memory

 echo 3 > /proc/sys/vm/drop_caches

完全釋放cache memory,必須先執行sync,避免錯誤。

sync

#在釋放記憶體後再將/proc/sys/vm/drop_caches的值設為0
echo 0 > /proc/sys/vm/drop_caches

釋放swap

 #此swap 在/dev/cobd1
 swapoff /dev/cobd1;swapon /dev/cobd1

常用記憶體指令

 free
 
 vmstat
 
 top
  
 watch cat /proc/meminfo

【crontab】排程相關

使用nginx 設定排程

sudo su -c "crontab -e" nginx -s /bin/bash

 

【vim】快速鍵

1. vi 編輯器中跳到檔案的第一行:

   a  輸入 :0 或者 :1   回車

   b  鍵盤按下 小寫 gg

2.vi 編輯器跳到檔案最後一行:

   a 輸入 :$   回車

   b 鍵盤按下大寫 G

   c 鍵盤按 shift + g    (其實和第二種方法一樣)

Vim快速移動游標至行首和行尾

  1、 需要按行快速移動游標時,可以使用鍵盤上的編輯鍵Home,快速將游標移動至當前行的行首。除此之外,也可以在命令模式中使用快捷鍵"^"(即Shift+6)或0(數字0)。

  2、 如果要快速移動游標至當前行的行尾,可以使用編輯鍵End。也可以在命令模式中使用快捷鍵"$"(Shift+4)。與快捷鍵"^"和0不同,快捷鍵"$"前可以加上數字表示移動的行數。例如使用"1$"表示當前行的行尾,"2$"表示當前行的下一行的行尾。

 

Vim多行註解

多行注释:

  1. 进入命令行模式,按ctrl + v进入 visual block模式(可视快模式),然后按j, 或者k选中多行,把需要注释的行标记起来

  2. 按大写字母I,再插入注释符,例如//

  3. 按esc键就会全部注释了(我的是按两下)

取消多行注释:

  1. 进入命令行模式,按ctrl + v进入 visual block模式(可视快模式),按小写字母l横向选中列的个数,例如 // 需要选中2列

  2. 按字母j,或者k选中注释符号

  3. 按d键就可全部取消注释

【Linux】時區設定

Centos7

timedatectl set-timezone Asia/Taipei

【Linux】載入順序

image-1677741051902.png

https://blog.miniasp.com/post/2021/07/26/Bash-and-Zsh-Initialization-Files

可以完整釐清 Bash 所有啟動檔的載入條件與順序,心裡的感覺格外踏實,非常棒! 👍

完整的 Zsh 啟動檔載入順序

由於許多 macOS 用戶都採用 Zsh 為主,這邊我也特別研究了一下 Zsh 的啟動檔載入順序,基本上 Zsh 會依據以下順序載入:

  1. ~/.zshenv

    任何啟動情境下,都會載入這個檔案,請將各種環境變數請全部設定在這裡。

  2. /etc/zsh/zprofile 與 ~/.zprofile

    如果執行在 Login shell 才會依序執行 /etc/zsh/zprofile 與 ~/.zprofile 檔案。

  3. /etc/zsh/zshrc 與 ~/.zshrc

    如果執行在 Interactive 互動模式下,才會依序執行 /etc/zsh/zshrc 與 ~/.zshrc 檔案。

  4. /etc/zsh/zlogin 與 ~/.zlogin

    如果執行在 Login shell 下,最後才會依序執行 /etc/zsh/zlogin 與 ~/.zlogin 檔案。

  5. ~/.zlogout 與 /etc/zsh/zlogout

    當你用 exit 或 logout 命令登出時,會自動依序執行 ~/.zlogout 與 /etc/zsh/zlogout 檔案。

我只能說,Zsh 的啟動順序實在比 Bash 好理解太多了,也沒什麼地雷! 👍

總結幾種常見情境

  1. 直接呼叫某個 Shell Script

    #!/bin/bash
    [ -z "$PS1" ] && echo "Non-Interactive" || echo "Interactive"
    shopt -q login_shell && echo "Login shell" || echo "Not login shell"
    
    • Interactive? 👉 No
    • Login shell? 👉 No
    • --noprofile? 👉 No

    執行時完全不會載入任何新的啟動檔設定!

  2. 使用 SSH 登入遠端主機

    ssh user@host
    

    依序載入 /etc/profile --> /etc/bash.bashrc --> ~/.profile [ -> ~/.bashrc ]

    • Interactive? 👉 Yes
    • Login shell? 👉 Yes
    • --noprofile? 👉 No

    注意: Bash 不會主動載入 ~/.bashrc 執行,而是我們通常在 ~/.profile 會載入 ~/.bashrc 執行。

  3. 使用 SSH 登入遠端主機後,執行 bash 命令

    ssh user@host
    

    剛登入,依序載入 /etc/profile --> /etc/bash.bashrc --> ~/.profile [ -> ~/.bashrc ]

    • Interactive? 👉 Yes
    • Login shell? 👉 Yes
    • --noprofile? 👉 No

    然後我們在遠端主機執行 bash 命令,進入下一層 Shell 環境:

    bash
    

    登入後執行 bash 預設是互動模式,會依序載入 /etc/bash.bashrc --> ~/.bashrc

    • Interactive? 👉 Yes
    • Login shell? 👉 No
    • --rcfile <file> ? 👉 No
    • --norc ? 👉 No
  4. 使用 SSH 登入遠端主機後,執行 bash -c '<command>' 命令

    ssh user@host
    

    剛登入,依序載入 /etc/profile --> /etc/bash.bashrc --> ~/.profile [ -> ~/.bashrc ]

    • Interactive? 👉 Yes
    • Login shell? 👉 Yes
    • --noprofile? 👉 No
    bash -c '[ -z "$PS1" ] && echo "Non-Interactive" || echo "Interactive"'
    

    登入後執行 bash -c 命令屬於非互動模式,而且沒有 $BASH_ENV 的情況下,不會載入任何啟動檔!

    • Interactive? 👉 No
    • Login shell? 👉 No
    • $BASH_ENV 👉 No
  5. 使用 SSH 執行遠端命令

    ssh user@host '[ -z "$PS1" ] && echo "Non-Interactive" || echo "Interactive"'
    ssh user@host 'shopt -q login_shell && echo "Login shell" || echo "Not login shell"'
    

    透過 SSH 執行遠端命令,預設將會跑在 Non-Interactive 模式下,但還是會依序載入 /etc/bash.bashrc --> ~/.bashrc

    • Interactive? 👉 No
    • Login shell? 👉 No

    如果你想在執行遠端命令時載入額外的啟動檔,也可以這樣寫:

    ssh user@host "source /etc/profile; source ~/.profile; /your/script.sh"
    
  6. 使用 SSH 執行遠端命令,透過 bash 呼叫另一個命令

    ssh user@host -t 'bash -c '"'"'[ -z "$PS1" ] && echo "Non-Interactive" || echo "Interactive"'"'"''
    ssh user@host -t 'bash -c '"'"'shopt -q login_shell && echo "Login shell" || echo "Not login shell"'"'"''
    

    要在單引號(')的字串中間加入一個單引號,必須輸入五個字元 '"'"' 才能代表一個單引號!(噁心的語法)

    在 ssh 執行時加入 -t 參數,可以在遠端執行時取得一個 pseudo-terminal allocation (pts/0)!

    透過 SSH 執行遠端命令,預設將會跑在 Non-Interactive 模式下,但還是會依序載入 /etc/bash.bashrc --> ~/.bashrc

    • Interactive? 👉 No
    • Login shell? 👉 No

    第二層 bash 應該是跑在 Non-Interactive 模式,但是卻依序載入 /etc/bash.bashrc --> ~/.bashrc 檔案,這部分我還沒辦法理解為什麼會這樣,感覺透過 SSH 執行遠端程式,預設就會載入這兩個檔案!

    • Interactive? 👉 No
    • Login shell? 👉 No

    底下這段是讓命令跑在 Interactive 模式,但載入啟動檔的順序竟然跟 Non-Interactive 竟然一樣!

    ssh user@host -t 'bash -i -c '"'"'[ -z "$PS1" ] && echo "Non-Interactive" || echo "Interactive"'"'"''
    ssh user@host -t 'bash -i -c '"'"'shopt -q login_shell && echo "Login shell" || echo "Not login shell"'"'"''
    

    簡單來說,使用 SSH 直接遠端命令時,使用 -i (互動模式) 或不使用 -i 對載入啟動檔沒有什麼兩樣,不過都會載入兩次。不過還是有一個地方不同,如果你的啟動檔有設定 alias 的話,只有使用 -i 互動模式才能使用。

    例如以下這段命令,就會得到 bash: ll: command not found 的錯誤:

    ssh user@host -t 'll'
    
    ssh user@host -t bash -c 'll'
    

    如果改用 -i 來執行,就可以正常執行 ll 這個 alias 命令:

    ssh user@host -t bash -i -c 'll'
    
  7. 使用 SSH 執行遠端命令,並以 Login shell 啟動 Bash

    ssh user@host bash -l -c 'set'
    

    第一層 bash 依序載入 /etc/bash.bashrc --> ~/.bashrc

    第二層 bash 依序載入 /etc/profile --> ~/.profile [ -> ~/.bashrc ]

【更新】Centos 7已於2024年6月30日停止維護,更換yum源解決yum404問題

 

mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
mv /etc/yum.repos.d/epel.repo /etc/yum.repos.d/epel.repo.backup

curl -o /etc/yum.repos.d/CentOS-Base.repo \
http://mirrors.vpnforgame.net/centos/7/CentOS-Base.repo

curl -o /etc/yum.repos.d/epel.repo \
http://mirrors.vpnforgame.net/epel/7/epel.repo

yum clean all

yum makecache

【Linux】DNS 相關

如何知道本機dns server 設定在哪

# 查詢/etc/resolv.conf 
cat /etc/resolv.conf 

# ip 出現 類似nameserver 127.0.0.53
# 代表不設定在本機 使用resolvectl
resolvectl status

##########################################
Global
       Protocols: -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
resolv.conf mode: stub

Link 2 (eth0)
    Current Scopes: DNS
         Protocols: +DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
Current DNS Server: 10.10.10.247
       DNS Servers: 10.10.10.246 10.10.10.247

【Linux】Dns 動態解析

若想實現同一個 DNS Server 根據不同來源 IP 返回不同的結果,這在 DNS 中稱為視圖(View)或基於來源的策略解析,以下是詳細實現方式。


使用 Bind 實現(最佳選擇)

Bind 支持基於來源 IP 的視圖配置,可以為不同來源的請求返回不同的 DNS 記錄。

配置步驟

  1. 安裝 Bind 安裝 Bind DNS Server:

    sudo apt install bind9
    
  2. 配置視圖(View) 編輯 Bind 的主配置文件 /etc/bind/named.conf,添加基於來源 IP 的視圖。

    範例配置:

    acl "internal-network" {
        192.168.1.0/24;
    };
    
    acl "external-network" {
        any;
    };
    
    view "internal" {
        match-clients { "internal-network"; };
        zone "example.com" {
            type master;
            file "/etc/bind/db.internal.example.com";
        };
    };
    
    view "external" {
        match-clients { "external-network"; };
        zone "example.com" {
            type master;
            file "/etc/bind/db.external.example.com";
        };
    };
    
  3. 創建區域文件 根據來源 IP 創建不同的區域文件。例如:

    • 內部網絡的區域文件 /etc/bind/db.internal.example.com

      $TTL 604800
      @   IN  SOA example.com. admin.example.com. (
              1   ; Serial
              604800 ; Refresh
              86400 ; Retry
              2419200 ; Expire
              604800 ) ; Negative Cache TTL
      ;
      @   IN  NS  ns.example.com.
      @   IN  A   192.168.1.1
      
    • 外部網絡的區域文件 /etc/bind/db.external.example.com

      $TTL 604800
      @   IN  SOA example.com. admin.example.com. (
              1   ; Serial
              604800 ; Refresh
              86400 ; Retry
              2419200 ; Expire
              604800 ) ; Negative Cache TTL
      ;
      @   IN  NS  ns.example.com.
      @   IN  A   203.0.113.1
      
  4. 重啟 Bind 重啟 Bind 服務:

    sudo systemctl restart bind9
    

使用 dnsmasq 實現(輕量級)

配置步驟

  1. 安裝 dnsmasq

    sudo apt install dnsmasq
    
  2. 配置條件解析 編輯 /etc/dnsmasq.conf,添加基於來源 IP 的條件解析規則:

    # 為內部網絡配置
    dhcp-range=set:internal,192.168.1.0,192.168.1.255
    address=/example.com/192.168.1.1
    
    # 為外部網絡配置
    dhcp-range=set:external,0.0.0.0,255.255.255.255
    address=/example.com/203.0.113.1
    
  3. 重啟 dnsmasq

    sudo systemctl restart dnsmasq
    

使用 PowerDNS(動態解析)

配置 PowerDNS + Lua 脚本

PowerDNS 支持使用 Lua 腳本進行動態解析。

  1. 安裝 PowerDNS 和相關組件

    sudo apt install pdns-server pdns-backend-sqlite3
    
  2. 啟用 Lua 腳本支持 在 /etc/powerdns/pdns.conf 中啟用 Lua Backend:

    launch=gsqlite3,lua
    lua-dns-script=/etc/powerdns/dns.lua
    
  3. 編寫 Lua 腳本 創建 /etc/powerdns/dns.lua,根據來源 IP 返回不同的結果:

    function postresolve(remoteip, domain, qtype)
        if string.match(remoteip, "^192%.168%.1%.") then
            return {{qtype="A", content="192.168.1.1", ttl=60}}
        else
            return {{qtype="A", content="203.0.113.1", ttl=60}}
        end
    end
    
  4. 重啟 PowerDNS

    sudo systemctl restart pdns
    

測試

使用 dig 測試

針對不同的來源 IP 測試返回的解析結果。


注意事項

  1. 來源 IP 檢測

    • 檢查網絡路由,確保 DNS 伺服器能正確檢測請求的來源 IP。
    • 若有 NAT 設置,需配置正確的來源地址。
  2. DNS 緩存

    • 若存在 DNS 緩存伺服器,可能會干擾條件解析結果。
  3. 性能

    • Bind 和 PowerDNS 適合高流量環境。
    • dnsmasq 適合輕量級應用場景。

這些方案可以靈活地根據來源 IP 實現不同的 DNS 解析結果。

【Linux】【權限管理】【acl】設定/var/www/html for tomcat 可讀寫

以下是如何在 Ubuntu 中設置這些 ACL 權限的步驟。


步驟 1:啟用 ACL 支持

如果 ACL 尚未啟用,請確保相關功能已經安裝並啟用:

  1. 安裝 ACL 工具:
    sudo apt install acl
    
  2. 確保文件系統支持 ACL:
    sudo mount -o remount,acl /
    

步驟 2:設置基本權限

設定 /var/www/html 的基本權限:

sudo chmod 775 /var/www/html
sudo chown root:root /var/www/html

步驟 3:配置 ACL 權限

根據需求逐步配置 ACL:

  1. 設置具體使用者和群組的 ACL 權限

    sudo setfacl -m u:tomcat:rwx /var/www/html
    sudo setfacl -m g::r-x /var/www/html
    sudo setfacl -m o::r-x /var/www/html
    
    • u:tomcat:rwx:給 tomcat 用戶設置 rwx 權限。
    • g::r-x:默認組的權限為 r-x
    • o::r-x:其他人的權限為 r-x
  2. 設置默認 ACL(適用於未來子目錄和文件)

    sudo setfacl -d -m u::rwx /var/www/html
    sudo setfacl -d -m u:tomcat:rwx /var/www/html
    sudo setfacl -d -m g::r-x /var/www/html
    sudo setfacl -d -m o::r-x /var/www/html
    
    • -d:表示設置默認 ACL(對新創建的文件/目錄生效)。

步驟 4:檢查 ACL 設置

使用以下指令檢查 ACL 配置是否正確:

getfacl /var/www/html

輸出應類似於:

# file: var/www/html
# owner: root
# group: root
user::rwx
user:tomcat:rwx
group::r-x
mask::rwx
other::r-x
default:user::rwx
default:user:tomcat:rwx
default:group::r-x
default:mask::rwx
default:other::r-x

ACL 設置的解釋

  1. 普通權限

    • user::rwx:目錄擁有者 root 的權限。
    • user:tomcat:rwx:為用戶 tomcat 設置的權限。
    • group::r-x:目錄的群組成員的權限。
    • other::r-x:其他用戶的權限。
    • mask::rwx:ACL 中權限的上限(最高可設置為 rwx)。
  2. 默認權限(default: 開頭)

    • default:user::rwx:默認擁有者的權限。
    • default:user:tomcat:rwx:默認為 tomcat 設置的權限。
    • default:group::r-x:默認群組的權限。
    • default:other::r-x:默認其他用戶的權限。

總結指令

以下是一鍵完成配置的指令集合:

sudo setfacl -m u:tomcat:rwx /var/www/html
sudo setfacl -m g::r-x /var/www/html
sudo setfacl -m o::r-x /var/www/html
sudo setfacl -d -m u::rwx /var/www/html
sudo setfacl -d -m u:tomcat:rwx /var/www/html
sudo setfacl -d -m g::r-x /var/www/html
sudo setfacl -d -m o::r-x /var/www/html

執行後確認權限是否正確,應與您列出的設定一致!


是否需要設定 -d 取決於您的需求,以下是有關 默認 ACL(-d 的詳細說明以及什麼情況下需要設定。


什麼是默認 ACL(-d)?

默認 ACL 是一組規則,會自動應用到 新創建的文件或子目錄 中。當一個目錄設置了默認 ACL,該目錄下創建的任何新文件或目錄都會繼承這些默認規則。


是否需要設定 -d

  1. 需要設定 -d 的情況

    • 如果您希望 新創建的文件或子目錄 自動繼承特定的 ACL 設置(如 tomcat 擁有特定權限),那麼您需要設置默認 ACL。例如:
      • /var/www/html 是一個共享的目錄,將會持續新增文件。
      • 您希望 tomcat 用戶對新增的文件有 rwx 權限。
    sudo setfacl -d -m u:tomcat:rwx /var/www/html
    

    當某人創建一個新文件時,tomcat 就會自動擁有該文件的權限。

  2. 不需要設定 -d 的情況

    • 如果您僅關心目錄 當前的文件和目錄,而不需要未來的新增文件繼承權限。
    • 如果您會手動或通過腳本為新文件設置權限,而不依賴默認 ACL。

    在這種情況下,您可以省略 -d,只設置當前的 ACL 即可:

    sudo setfacl -m u:tomcat:rwx /var/www/html
    

範例:對比是否設置 -d 的效果

假設您在 /var/www/html 下創建了兩個文件:

  1. 沒有設置 -d 的情況

    • 當您創建新文件時,不會繼承 tomcat 的權限。
    • 新文件的權限取決於當前的系統默認值(如 umask)。
  2. 設置了 -d 的情況

    • 新文件或目錄將繼承默認 ACL。例如,tomcat 將擁有對新文件的權限:
      touch /var/www/html/newfile
      getfacl /var/www/html/newfile
      
      結果顯示 tomcat 的權限被自動應用。

結論

建議根據場景選擇適合的設置,以滿足項目需求。

【Linux】SSH 跳板機設定

如果你經常需要透過主機A跳到主機B進行操作,可以考慮以下幾種方法來提升效率:

1. SSH 跳板機設定 (ProxyJump 或 ProxyCommand)

你可以在 ~/.ssh/config 檔案中設定跳板機 (主機A) 和目標主機 (主機B)。

方法一:使用 ProxyJump (推薦,簡潔且較新)

   Host 主機B
       HostName <主機B的IP或主機名>
       User <使用者名稱>
       ProxyJump <主機A的使用者名稱>@<主機A的IP或主機名>

使用這個設定後,你可以直接用 ssh 主機B 連接到主機B,不需先登入主機A。

方法二:使用 ProxyCommand (舊版本支援)

   Host 主機B
       HostName <主機B的IP或主機名>
       User <使用者名稱>
       ProxyCommand ssh <主機A的使用者名稱>@<主機A的IP> -W %h:%p

這個設定同樣讓你直接 ssh 主機B 連接到主機B。


2. SSH 快速別名設定 (使用別名簡化命令)

你也可以在 ~/.bashrc 或 ~/.zshrc 中設定別名,直接執行一個指令來登入主機B。

alias sshB='ssh -J <主機A的使用者名稱>@<主機A的IP或主機名> <主機B的使用者名稱>@<主機B的IP或主機名>'

之後,你只需要輸入 sshB 就能登入主機B。


3. 使用 SSH Multiplexing (重複利用 SSH 連線)

如果你需要頻繁連線到同一個主機,可以開啟 SSH 連線複用功能,減少重複登入的時間:

在 ~/.ssh/config 加入以下內容:

Host *
    ControlMaster auto
    ControlPath ~/.ssh/control-%r@%h:%p
    ControlPersist 10m

這樣在第一次登入主機A時,SSH 會保持連線,之後登入主機B就會變得更快。


4. 使用 SSH Agent 轉發 (Agent Forwarding)

如果主機A和主機B需要同一組 SSH 金鑰,可以使用 SSH Agent Forwarding,避免在主機A上存放私鑰:

ssh -A <主機A的使用者名稱>@<主機A的IP>
ssh <主機B的使用者名稱>@<主機B的IP>

或者在 ~/.ssh/config 啟用 Agent Forwarding:

Host 主機A
    ForwardAgent yes

這樣就能直接將本地端的 SSH 金鑰轉發到主機A,並用來登入主機B。


5. 使用 tmux 或 screen (維持長時間工作環境)

如果你的操作過程需要持續很長時間,建議在主機A或B上使用 tmux 或 screen 來保持工作環境,這樣即使斷線也能恢復。

安裝並啟動 tmux:

tmux new -s session_name

之後可以斷開連線並重新附加:

tmux attach -t session_name

6. 使用 Ansible 自動化操作 (進階)

如果你有固定的操作流程,可以使用 Ansible 寫 Playbook,批量操作多個主機,包括跳板機情境:

- name: Jump to 主機B via 主機A
  hosts: 主機B
  vars:
    ansible_ssh_common_args: '-o ProxyJump=<主機A的使用者名稱>@<主機A的IP>'
  tasks:
    - name: Run shell command
      command: <你的shell指令>

使用 Ansible 來批量執行,避免手動登入和操作。


這幾個方法可以根據需求選擇,ProxyJump 和 SSH Config 設定最為方便、簡潔,推薦優先使用!

【Tool】tmux

📦 tmux 簡易說明

tmux(Terminal Multiplexer)是一個強大的終端複用工具,可以在單一終端視窗中同時管理多個工作階段(sessions)、視窗(windows)、與窗格(panes)。


🚀 tmux 的核心概念

  1. Session(工作階段)

    • 一個 tmux session 可以包含多個視窗,像是一個獨立的工作空間。
    • 支援在背景運行,即使關閉終端也不會中斷。
    • image-1739418422966.png

  2. Window(視窗)

    • 每個 session 裡可以有多個視窗,每個視窗類似一個完整的終端畫面。
    • 視窗可分割成多個窗格,方便同時監控多個任務。
    • image-1739418697038.png

  3. Pane(窗格)

    • 視窗內的分割區域,每個窗格可獨立執行命令。
    • 支援水平與垂直分割,方便進行多任務操作。
    • image-1739418735165.png


安裝 tmux

Ubuntu 安裝 tmux

Ubuntu 官方倉庫提供了 tmux,可直接使用 apt 安裝:

sudo apt update
sudo apt install tmux -y

macOS 安裝 tmux

macOS 用戶可以透過 Homebrew 安裝:

brew install tmux

🔍 更新或移除 tmux
Ubuntu
macOS

⌨️ 常用指令快速上手

功能 指令 / 快捷鍵 說明
 session
啟動 tmux tmux 開啟一個新的 tmux session
  tmux new -s 名稱   開啟一個新的 tmux session 使用自訂名稱
查看所有 session tmux ls 列出目前所有 tmux session
切換 session Ctrl-b s

圖形化切換session

(如果該session 內有多視窗,可按 -> 選擇換到該視窗)

離開 tmux(保持運行) Ctrl-b d 分離 session,回到原本終端
離開 tmux(結束此session) Ctrl-b x 結束目前session,回到原本終端
重新連接 session tmux attach -t 名稱 重新連接到未結束的 session
  tmux a  重新連接上次中斷seeion
刪除 session 

tmux kill-session -t 名稱

刪除指定名稱session
刪除所有 session 

tmux kill-server

 
重新命名 session Ctrl-b $ 當前session 改名
  tmux rename-session -t 舊名稱 新名稱 修改指令 session 名稱
window
建立新視窗 Ctrl-b c 建立一個新的視窗
切換視窗 Ctrl-b w 圖形化切換window
  Ctrl-b 視窗編號  
  Ctrl-b n / p 切換到下一個/上一個視窗
關閉視窗 Ctrl-b & 關閉當前視窗
重新命名 window Ctrl-b , 更名目前window
  tmux rename-window -t 舊名稱 新名稱 更名指定window
Pane
分割窗格(垂直) Ctrl-b " 垂直分割出新窗格
分割窗格(水平) Ctrl-b % 水平分割出新窗格
切換窗格 Ctrl-b 方向鍵 在窗格間切換
  vi  ~/.tmux.conf 
加入set  -g mouse on

使用滑鼠切換

使用滑鼠調整分割線

關閉窗格 Ctrl-b x

 

與上一格窗格互換 Ctrl-b {

 

與下一格窗格互換 Ctrl-b }

 

顯示窗格編號 Ctrl-b q

 

指定窗格互換 tmux swap-pane -s 1 -t 2

 

其他
命令模式 Ctrl-b : 進入命令模式,可執行 tmux 指令
配置設定檔

vi ~/.tmux.conf

set -g mouse on

:支持滑鼠

set -g prefix C-s

:ctrl + b前缀改成ctrl + s

 

當滑鼠模式關閉(set -g mouse off)時,作業系統提供的標準複製/貼上功能將如預期運作。
滑鼠模式開啟(set -g mouse on)時,剪貼簿的功能會造成失效
下面的程式碼可以新增到您的 .tmux.conf 檔案中,以將m和M鍵分別綁定到「滑鼠開啟」和「滑鼠關閉」。

這讓你能夠使用Ctrl+ B,m來開啟滑鼠支援;Ctrl+ B,M將其關閉。

vi ~/.tmux.conf



###############################################
# toggle mouse mode to allow mouse copy/paste
# set mouse on with prefix m
bind m \
    set -g mouse on \;\
    display 'Mouse: ON'
# set mouse off with prefix M
bind M \
    set -g mouse off \;\
    display 'Mouse: OFF'        

參考:https://stackoverflow.com/questions/17445100/getting-back-old-copy-paste-behaviour-in-tmux-with-mouse


🎯 常見使用情境


常見問題

已在某session 內要新建session 

image-1739416150135.png

或是要切換到另一個session

image-1739416354391.png

這代表 你已經在一個 tmux session 裡,然後又試圖附加(attach)到另一個 session。tmux 預設不建議這種「嵌套 session」的行為,因為可能會導致控制鍵衝突或混亂。

建議方式:

建立session:離開tmux 模式Ctrl-b d,在建立新的session : tmux or tmux new -s 名稱

切換session: Ctrl-b s 切換 or tmux switch-client -t 名稱

image-1739416638882.png


 

以下是 tmux 快速鍵表格:

快速鍵 功能說明
C-b Space 選擇下一個佈局
C-b ! 將窗格分離到新視窗
C-b " 垂直分割視窗
C-b # 列出所有剪貼簿
C-b $ 重新命名當前工作階段
C-b % 水平分割視窗
C-b & 關閉當前視窗
C-b ' 輸入視窗索引以切換
C-b ( 切換到上一個客戶端
C-b ) 切換到下一個客戶端
C-b , 重新命名當前視窗
C-b - 刪除最近的剪貼簿
C-b . 移動當前視窗
C-b / 顯示按鍵綁定說明
C-b 0~9 選擇對應編號的視窗
C-b : 輸入命令提示符
C-b ; 切換到上次使用的窗格
C-b = 從清單中選擇剪貼簿
C-b ? 列出所有按鍵綁定
C-b C 自訂選項
C-b D 從清單中選擇並分離客戶端
C-b E 平均分配所有窗格
C-b L 切換到最後一個客戶端
C-b M 清除標記的窗格
C-b [ 進入複製模式
C-b ] 貼上最近的剪貼簿
C-b c 建立新視窗
C-b d 分離當前客戶端
C-b f 搜尋窗格
C-b i 顯示視窗資訊
C-b l 切換到上個視窗
C-b m 標記或取消標記窗格
C-b n 選擇下一個視窗
C-b o 選擇下一個窗格
C-b p 選擇上一個視窗
C-b q 顯示窗格編號
C-b r 重新整理當前客戶端
C-b s 從清單中選擇工作階段
C-b t 顯示時鐘
C-b w 從清單中選擇視窗
C-b x 關閉當前窗格
C-b z 放大/還原當前窗格
C-b { 與上方窗格交換位置
C-b } 與下方窗格交換位置
C-b ~ 顯示訊息
C-b DC 重置視窗以跟隨游標
C-b PPage 進入複製模式並向上捲動
C-b ↑/↓/←/→ 選擇相對方向的窗格
C-b M-1~M-7 設定不同的視窗佈局
C-b M-n 選擇下一個有警示的視窗
C-b M-o 反向循環切換窗格
C-b M-p 選擇上一個有警示的視窗
C-b M-↑/↓/←/→ 調整窗格大小 (每次5個單位)
C-b C-b 傳送前綴鍵
C-b C-o 循環切換窗格
C-b C-z 暫停當前客戶端
C-b C-↑/↓/←/→ 調整窗格大小
C-b S-↑/↓/←/→ 移動視窗的可見部分

Reference

【Linux】【Ubuntu】 中更改 hostname

在 Ubuntu 中更改 hostname 有兩種常見方式,以下提供完整步驟:


1️⃣ 使用 hostnamectl(推薦方式,Ubuntu 16.04 之後)

hostnamectl 是 systemd 提供的指令,可同時修改 暫時永久 主機名稱。

# 查看當前 hostname
hostnamectl status

# 修改 hostname,例如改成 my-server
sudo hostnamectl set-hostname my-server

⚠️ 有時候 shell 提示字仍顯示舊名稱,重新登入 SSH 或 su - $USER 會看到更新。


2️⃣ 手動編輯設定檔

如果是較舊版本或想手動修改,可直接編輯以下兩個檔案:

  1. /etc/hostname

    sudo nano /etc/hostname
    

    把原本的名稱改成新的,如 my-server

  2. /etc/hosts

    sudo nano /etc/hosts
    

    找到類似:

    127.0.1.1    old-hostname
    

    改成:

    127.0.1.1    my-server
    

    這步驟避免本機解析錯誤。

  3. 重新啟動或執行:

    sudo systemctl restart systemd-logind
    

    或乾脆 sudo reboot


補充建議


總結

建議使用 sudo hostnamectl set-hostname <新名稱>
這是最簡單且官方推薦的方式,重登入即可生效。

【 Linux】Ubuntu 擴充硬碟完整步驟

 

 Proxmox / Ubuntu 擴充硬碟完整步驟

💡 目標:

將原本的 /dev/sda 從 78G 擴充到 200G(或更大),
並讓 /(根目錄)可使用整個新容量。

【proxmox】先使用ui +  disk

image-1759893318494.png


一、確認目前磁碟架構

lsblk

範例輸出:

sda
├─sda1  1M   BIOS boot
├─sda2  2G   /boot
└─sda3  78G  LVM → ubuntu--vg → ubuntu--lv → /

檢查磁碟實際大小:

sudo fdisk -l /dev/sda

確認 sda3 沒有覆蓋整顆磁碟(例如結束 sector 明顯在中段)。


二、調整分區(fdisk 擴大 /dev/sda3)

⚠️ 這步只修改分區表,不會刪資料。
關鍵是「Start sector 不變」,這樣 LVM 仍能識別。

sudo fdisk /dev/sda

依序輸入以下指令(每行結束按 Enter):

Command (m for help): p
Command (m for help): d
Partition number (1-3, default 3): 3
Command (m for help): n
Partition number (3-128, default 3): 3
First sector (4198400-419430366, default 4198400): 4198400
Last sector, +/-sectors or +/-size{K,M,G,T,P} (4198400-419430366, default 419430366): [直接 Enter 使用預設值]

當出現:

Partition #3 contains a LVM2_member signature.
Do you want to remove the signature? [Y]es/[N]o:

👉 輸入 N(No)保留資料!

繼續:

Command (m for help): t
Partition number (1-3, default 3): 3
Hex code or alias (type L to list all): 8e
Command (m for help): w

三、重新讀取分區表

sudo partprobe

若出現 busy 警告,可忽略 /dev/sr0,只要 /dev/sda3 沒報錯即可。
如有報錯,可重開機一次再繼續。


四、擴大 LVM 實體卷(PV)

sudo pvresize /dev/sda3

檢查是否成功:

sudo vgdisplay

你應該看到:

Free  PE / Size       >0 / 約120GiB

五、擴大邏輯卷(LV)

sudo lvextend -l +100%FREE /dev/ubuntu-vg/ubuntu-lv

範例輸出:

Size of logical volume ubuntu-vg/ubuntu-lv changed from <78.00 GiB to <198.00 GiB

六、擴大檔案系統(線上擴充)

先確認檔案系統類型:

df -Th /

結果可能是:

/dev/mapper/ubuntu--vg-ubuntu--lv ext4 ...

▸ 若是 ext4:

sudo resize2fs /dev/ubuntu-vg/ubuntu-lv

▸ 若是 xfs:

sudo xfs_growfs /

七、驗證結果

df -h

預期結果:

Filesystem                         Size  Used Avail Use% Mounted on
/dev/mapper/ubuntu--vg-ubuntu--lv  196G   20G  170G  11% /

✅ 狀態總結

項目 結果
分區 /dev/sda3 已擴大到整顆磁碟
PV (pvresize) 已更新容量
VG / LV (lvextend) 成功放大
檔案系統 (resize2fs) 線上擴充完成
是否需重開機 ❌ 不需要

💡 小提醒


 

【Linux】swap相關

 

image-1766024226901.png

從你貼的 top 看起來 Swap 使用率偏高KiB Swap: 79.8/1044476 很像是 79.8% / 1,044,476 KiB),要「釋放 swap」本質上就是把已經換到 swap 的頁面搬回 RAM。最直接的方法是 swapoff → swapon(會短暫吃 RAM、可能卡頓一下)。

✅ 1) 先確認 RAM 夠不夠(很重要)

free -h
swapon --show

available(可用記憶體)要 大於目前 swap 已用量(最好再多留一些 buffer),不然 swapoff 可能 OOM 或把機器拖很慢。

[root@localhost ~]# free -h 
total used free shared buff/cache available 
Mem: 45G 25G 1.8G 226M 18G 20G 
Swap: 1.0G 814M 205M 

[root@localhost ~]# swapon --show 
NAME TYPE SIZE USED PRIO 
/dev/dm-1 partition 1020M 814.2M -2

✅ 2) 一次清空 swap(常用)

sudo swapoff -a
sudo swapon -a

清完再確認:

free -h
swapon --show

若你是 swapfile(例如 /swap.img/swapfile),也可只針對單一檔案:

sudo swapoff /swap.img   # 或 /swapfile
sudo swapon  /swap.img

✅ 3) 找出「誰在吃 swap」(不然很快又會回來)

有 smem 最方便

sudo apt-get update && sudo apt-get install -y smem
sudo smem -rs swap | head

沒有 smem:用 /proc 快速抓(由大到小)

# who_use_swap.sh
#!/bin/bash
for p in /proc/[0-9]*; do
  pid=${p##*/}
  swap=$(awk '/VmSwap:/ {print $2}' $p/status 2>/dev/null)
  comm=$(tr -d '\0' < $p/comm 2>/dev/null)
  if [ -n "$swap" ] && [ "$swap" -gt 0 ]; then
    printf "%10s KiB  pid=%s  %s\n" "$swap" "$pid" "$comm"
  fi
done | sort -nr | head -20

⚠️ 小提醒:swapoff 期間會把資料搬回 RAM,可能造成短暫卡頓/IO 增加;如果是線上服務,建議離峰做,或先找出吃 swap 的程序再處理。


✅ swapoff 如何觀察?

watch 最方便:

watch -n 5 free -h

想加上時間戳一起看:

watch -n 5 'date; echo; free -h'

離開按 q(或 Ctrl+C)。

Every 5.0s: date; echo; free -h                                                                    
Thu Dec 18 10:23:47 2025

Thu Dec 18 10:23:47 CST 2025

              total        used        free	 shared  buff/cache   available
Mem:            45G         25G        994M        230M         18G         19G
Swap:          1.0G          0B        1.0G

 

✅ 什麼情況才需要「清快取」?

以下有需要放快取,獲得記憶體空間嗎

Every 5.0s: date; echo; free -h                                                                    
Thu Dec 18 10:23:47 2025

Thu Dec 18 10:23:47 CST 2025

              total        used        free	 shared  buff/cache   available
Mem:            45G         25G        994M        230M         18G         19G
Swap:          1.0G          0B        1.0G

你現在重點要看的是:

所以:沒有必要清 cache,清了反而會讓磁碟/檔案讀取變慢(cache 被你清掉了)。

 


✅ 如何判斷「到底有沒有影響」:

vmstat 1

si / so(swap in / swap out):

[root@localhost ~]# vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 2  0 354480 1360744    788 19839980    0    0     0    16    0    0  2  1 97  0  0
 1  0 354040 1360720    788 19840012  440    0   440   778 10902 12281  2  7 91  0  0
 2  0 353108 1357988    788 19840088  932    0   932    83 14391 17944  5  8 87  0  0
 2  0 352616 1355888    788 19840140  460    0   460   117 15671 19400  7  8 85  0  0
 3  0 351912 1357268    788 19840132  640    0   640   142 15713 19048  5  8 87  0  0
 2  0 351448 1355556    788 19840140  436    0   436    92 13794 15914  2  8 90  0  0
 2  0 350628 1357180    788 19840156  720    0   720   174 18513 21545  4  9 87  0  0
 1  0 349144 1355736    788 19840136 1484    0  1484    77 11470 13126  2  7 91  0  0
 2  0 348476 1354372    788 19840136  668    0   668    79 11530 12891  2  7 91  0  0
^C

你這段 vmstat 1 顯示「swap 正在被讀回 RAM」,而且是連續的:

這代表:有程式正在碰到曾經被換到 swap 的記憶體頁面,系統就把它從 swap 讀回來;目前沒有再把新的頁面換出去。

會有什麼影響?

  1. 尾延遲抖動(最典型)
    只要 si 不為 0,就表示有 swap I/O;那段時間碰到這些頁面的 thread 可能會卡一下(但你 wa=0 表示目前 I/O 沒被堵住,所以感受可能不明顯或很輕微)。

  2. swap 滿會降低緩衝空間
    現在 so=0 代表還沒再把東西換出去;但如果之後遇到瞬間記憶體壓力,swap 已滿會讓系統更容易走向 OOM / 更劇烈 reclaim。


✅ swap 不清會有什麼影響

不清 swap 通常不會有立即性壞處,但會有幾個「可能的影響」,看你的工作型態而定:

1) 效能:偶爾的延遲抖動(最常見)

swap 裡的資料如果之後又被用到,就會發生 page-in(從磁碟/SSD 讀回 RAM),比 RAM 慢很多,所以可能出現:

你現在 swap 只有 520MB,通常影響不大;但若剛好那 520MB 裡面是常被碰到的頁面,就會感覺得到。

2) 反映「過去曾經記憶體吃緊」

swap 被用滿常代表之前某個時段 RAM 壓力大(尖峰、記憶體洩漏、或短時間大量 cache / buffer / workload)。

3) swap 滿了之後的風險:下次再吃緊會更容易出事

swap 如果已經 100%:

4) 不清 swap 本身不會「佔著 RAM」

很多人誤會:swap 滿了會把 RAM 壓縮。其實 swap 佔的是磁碟區塊,不會直接吃掉你的 RAM。
你真正該看的仍是 available、以及是否有頻繁 swap in/out。


✅ 説明 /dev/dm-1 意義 , 與 -a 哪裡不同
sudo swapoff /dev/dm-1
sudo swapon /dev/dm-1

好,先用你現在看到的資訊來對照講:

/dev/dm-1 是什麼意思?

想看它真正對應到什麼名字(建議你查一下):

ls -l /dev/dm-1
lsblk -f
sudo dmsetup info -C
sudo dmsetup ls --tree

通常你會看到像 centos-swapvgname-swap 之類的 LV 名稱。

 


-a 跟指定 /dev/dm-1 有什麼不同?

1) 作用範圍不同

2) 安全性/可控性不同

3) -a 依賴 /etc/fstab


你這台怎麼選?

你現在 swapon --show 只有一個 /dev/dm-1,所以:


✅ 降低未來再大量使用 swap(可選)

sudo sysctl -w vm.swappiness=10

要永久生效:

echo 'vm.swappiness=10' | sudo tee /etc/sysctl.d/99-swappiness.conf
sudo sysctl --system

sudo sysctl -w vm.swappiness=10 這行是在 「立即」調整 Linux kernel 對 swap 的使用傾向


等價於:

echo 10 | sudo tee /proc/sys/vm/swappiness

vm.swappiness 代表什麼?

範圍(常見)

很多人會用 10 或 1 來降低 swap 對延遲的影響(尤其是 DB、API、線上服務)。


調成 10 的「實際效果」

常見誤解:swappiness=10 會把現有 swap 清掉嗎?

不會。

swapoff -a && swapon -a

風險 / 代價是什麼?

你的機器 RAM 45G、swap 很小(520M~1G),把 swappiness 降到 10 通常是合理的偏好:少 swap、降低抖動。


這設定會持久嗎?

不會。重開機會還原。

要永久化:

echo 'vm.swappiness=10' | sudo tee /etc/sysctl.d/99-swappiness.conf
sudo sysctl --system

建議你怎麼驗證有沒有幫助?

改完後觀察:

vmstat 1

so(swap out)是否長期維持 0,系統是否少出現延遲抖動。

如果你願意貼 cat /proc/sys/vm/swappiness 以及你的服務類型(DB / API / ELK / Docker host),我可以給你更適合的 swappiness 建議值。