2024年6月28日 星期五

[Linux] vim 使用筆記

模式 (mode)

一開始認識 vim就要先了解其不同的模式:

  • 普通模式 (Normal Mode)
  • 插入模式 (Insert Mode)
  • 命令列模式 (Command Line Mode)
  • 可視模式 (Visual Mode)

其中最常用是一般模式 (Normal Mode)、插入模式 (Insert Mode)及命令列模式 (Command Line Mode)。一開始進入 vim時的模式為普通模式, 其他模式都要經過普通模式進入,透過 Esc鍵返回。

普通模式 (Normal Mode)


游標移動
h or [←]游標向左移動一個字元
j or [↓]游標向下移動一個字元
k or [↑]游標向上移動一個字元
l or [→]游標向右移動一個字元
可以在指令前加上要執行指令的次數,例如 20l or 20[→],就可以往右移動 20個字元。
[Ctrl] + b or [PgUp]向上移動一頁 (backward)
[Ctrl] + f or [PgDn]向下移動一頁 (forward)
[Ctrl] + u 向上移動半頁 (upward)
[Ctrl] + d 向下移動半頁 (downward)
0 or [Home] 移動到此列的起始位置
$ or [End] 移動到此列最後面非空字元
^ 移動到此列最前面非空字元
+ 移動到下一列最前面的非空字元
- 移動到上一列最前面的非空字元
gg 移動到檔案的第一行
G 移動到檔案的最後一行
{number}G 可以移動到第 {number}行,例如 20G,可以移動到檔案第 20行
H 移動到目前顯示的第一行首字元
M 移動到目前顯示的中間一行首字元
L 移動到目前顯示的最後一行首字元
[Space] 向右移動一個字元
[Enter] 移動到下一行
{number}[Space]可以向右移動 {number}個字元,與[→]不同的是,[Space]會移動到下一行。 {number}[Enter]可以向下移動 {number}行。

搜尋與取代
/{string}向後搜尋 {string}字串
?{string}向前搜尋 {string}字串
n執行上一個搜尋操作
N反向執行上一個搜尋操作
s/{string1}/{string2}/g將此行的 {string1}取代成 {string2}
%s/{string1}/{string2}/g將檔案裡的 {string1}取代成 {string2}
%s/{string1}/{string2}/gc將檔案裡的 {string1}取代成 {string2},取代前需要確認

編輯
x刪除游標後面的字元
X刪除游標前面的字元
dd刪除游標所在的這一行
{number}X及 {number}x可以刪除游標前、後 {number}個字元。 {number}dd可以刪除游標往下 {number}行。
d1G刪除游標到第一行中的內容
dG刪除游標到最後一行的內容
d0刪除游標前的這一行的內容
d$刪除游標後的這一行的內容
yy複製游標所在的這一行 (yank)
{number}yy可以複製游標往下 {number}行。
y1G複製游標到第一行中的內容
yG複製游標到最後一行的內容
y0複製游標前的這一行的內容
y$複製游標後的這一行的內容
p在游標的後一行貼上
P在游標的前一行貼上
J將此行與下一行合成同一行
u回到上一個操作的狀態 (undo)
[Ctrl] + r回到下一個操作的狀態 (redo)
.重複上一個操作

插入模式 (Insert Mode)


進入插入模式
i在游標字元處前插入 (insert)
I從此行第一個非空字元前插入
a在游標字元處後插入 (append)
A從此行最後字元後插入
o插入新的下面一行 (open)
O插入新的上面一行
r進入取代模式,只取代一個字元 (replace)
R進入取代模式,直到離開

命令列模式 (Command Line Mode)


Command Line Mode指令
:w儲存目前檔案變更 (write)
:q離開 vim (quit)
:w!可以強制寫入唯讀檔案。:q!可以強制不儲存離開。
:wq儲存並離開
ZZ若檔案沒有修改,直接離開。若檔案有修改,儲存並離開
ZQ不儲存離開
:w {filename}將檔案另存到 {filename}
:r {filename}將另外一個檔案的內容加到游標位置的下一行
:! {command}暫時離開 vim並執行 {command}
vim 可以同時打開多個檔案進行編輯。ex: vim a.txt b.txt。
:files列出目前 vim所開啟的檔案
:n編輯下一個檔案
:N編輯上一個檔案

可視模式 (Visual Mode)


Visual Mode指令
v將游標經過的字元反白選擇
V將游標經過的行反白選擇
[Ctrl + v]以blcok的方式進行反白選擇
y複製選擇的內容
d刪除選擇的內容
p貼上選擇的內容

參考連結:
鳥哥私房菜 第九章、vim程式編輯器

2024年6月2日 星期日

[Python] threading

在閱讀關於 python multi-thread(多執行緒)、multi-process(多行程)及GIL的相關文章時,突然想到在公司寫的一個 script。 這 script需要使用同個 api發送不同參數的HTTP request,一開始的寫法是使用 for loop來執行,等到 request結束,再執行下一個。

由於每個 request需要幾十秒才會完成,所以整個 sciprt跑完就要花費好幾分鐘。如果能改寫成 使用 multi-thread的方式來發送 request,就能省下大量的時間。因為 GIL的關係,同時間只會 有一個 thread在執行,但以這 case來說已經很夠用了。

以下是要修改的 sample code,使用 for loop來執行 20次的 request:

import requests

def do_request(url):
    response = requests.get(url)
    print(response.status_code)
    return response

if __name__ == '__main__':
    for i in range(0, 20):
        ret = do_request("https://api.github.com")
        print (ret.json())

使用 python threading來改寫:

import requests
import threading

def do_request(url):
    response = requests.get(url)
    print(response.status_code)
    return response

if __name__ == '__main__':
    thread_list = []
    for i in range(0, 20):
        t = threading.Thread(target=do_request, args=("https://api.github.com",))
        thread_list.append(t)
        t.start()

    for t in thread_list:
        t.join()


宣告 Thread


t = threading.Thread(target=do_request, args=("https://api.github.com",))

建立一個 Thread物件,將要使用 threads來執行的 function傳入 target,並把 target所需要的引數以 tuple的形式傳入 args。


啟動 Thread


t.start()

透過呼叫 start來啟動此 thread。


等待 Thread執行完成


t.join()

使用 join來等待此 thread結束。這裡使用 for loop來等待所有的 thread結束。 若沒有使用 join,thread可能會在主程式後才執行完成。


獲得 Thread的返回值

上面的程式碼雖然可以讓函式使用 thread的方式執行,卻沒辦法得到函式的返回值。其中一個解法是將函式改寫,使其將返回值存到 list中。

import requests
import threading

def do_request(url, index, response_list):
    response = requests.get(url)
    print(response.status_code)
    response_list[index] = response

if __name__ == '__main__':
    thread_list = []
    response_list = [None] * len(range(0, 20))
    for i in range(0, 20):
        t = threading.Thread(target=do_request, args=("https://api.github.com", i, response_list))
        thread_list.append(t)
        t.start()

    for t in thread_list:
        t.join()

    print(response_list)

參考資料:
https://docs.python.org/zh-tw/3/library/threading.html
https://realpython.com/intro-to-python-threading/


2024年3月24日 星期日

[BMC] ipmitool 命令列表

官方網址:

https://github.com/ipmitool/ipmitool


bmc

顯示 bmc相關資訊

ipmitool bmc info

顯示當前 bmc已啟用選項

ipmitool bmc getenables

啟用/停用 bmc選項

ipmitool bmc setenables <OPTION>=[on|off]

option desctiption
recv_msg_intr Receive Message Queue Interrupt
event_msg_intr Event Message Buffer Full Interrupt
event_msg Event Message Buffer
system_event_log System Event Logging
oem0 OEM-Defined option #0
oem1 OEM-Defined option #1
oem2 OEM-Defined option #2

啟用 Event Message Buffer
ipmitool bmc setenables event_msg=on

停用 Event Message Buffer
ipmitool bmc setenables event_msg=off



sensor

顯示當前 sensor的資訊

ipmitool sensor list

透過 Sensor ID讀取特定 sensor的資訊

ipmitool sensor get "<SERDOR_ID>"


chassis

顯示當前 chassis狀態

ipmitool chassis status

power

顯示當前 chassis的電源狀態

ipmitool chassis power status
ipmitool power status

開啟電源

ipmitool chassis power on
ipmitool power on

關閉電源

ipmitool chassis power off
ipmitool power off

重啟電源

ipmitool chassis power reset
ipmitool power reset

關閉電源後開啟電源

ipmitool chassis power cycle
ipmitool power cycle

更改開機裝置

ipmitool chassis bootdev <device>

device desctiption
none Do not change boot device order
pxe Force PXE boot
disk Force boot from default Hard-drive
diag Force boot from Diagnostic Partition
cdrom Force boot from CD/DVD
bios Force boot into BIOS Setup
floppy Force boot from Floppy/primary removable media

Clear CMOS

ipmitool chassis bootdev none clear-cmos=yes


user

顯示 user在 channel的相關資訊

ipmitool user list <CHANNEL_ID>

顯示 channel 1的 user資訊
ipmitool user list 1


設定 user的名稱

ipmitool user set name <USER_ID> <USER_NAME>

設定 user id 2的名稱為 testuser
ipmitool user set name 2 testuser


設定 user的密碼

ipmitool user set password <USER_ID> <USER_NAME>

設定 user id 2的密碼為 test
ipmitool user set password 2 test


啟用 BMC存取

ipmitool user enable <USER_ID>

啟用 user id 2的 BMC存取
ipmitool user enable 2


停用 BMC存取

ipmitool user disable <USER_ID>


channel

顯示 channel的資訊

ipmitool channel info <CHANNEL_ID>

顯示 channel 1的資訊
ipmitool channel info 1


設定 user存取 channel

ipmitool channel setaccess <CHANNEL_ID> <USER_ID> [callin=on|off] [ipmi=on|off] [link=on|off] [privilege=<level>]

設定 user id 2在 channel 1的 ipmi on及privilege level為 4
ipmitool channel setaccess 1 2 ipmi=on privilege=4



2024年3月9日 星期六

機械式硬碟相關名詞

最近在讀早期 linux kernel的相關書籍,其在塊設備章節提到 hard disk controller(硬碟控制器)有很多機械硬碟物理層面的相關名詞。 因為這時的 hd controller的操作使用底層的細節,用於操作硬碟控制器的命令參數。



示意圖中是以 3個磁盤(Platters)及 6個磁頭 (Heads)所組成的硬碟,磁盤的兩面都能讀寫。硬碟主要以兩組馬達控制,一組控制磁盤的旋轉,另一組控制磁頭的移動。

Sector (磁區,扇區)
磁區是磁盤上以相同的角度劃出的等分區域,也是硬碟最小的讀寫單位,最開始統一的單位為 512 Bytes。

Track (磁軌,磁道)
磁軌是磁頭在磁盤上以相同半徑所畫出的軌跡。

Cylinder (磁柱,柱面)
磁柱是所有磁盤上相同半徑的磁道所形成的圓柱體。

CHS 定址

早期的硬碟定址使用 Cylinder-Head-Sector方法,從上方的硬碟物理構造可以看出,以這三個參數就能定位到某個確定的磁區。這方法在之後被 LBA(Logic Block Address)所取代。

2024年1月15日 星期一

com0com - Null modem emulator

官方網址:
https://com0com.sourceforge.net/

com0com可以在 Windows下虛擬出一組對接com port。

安裝完後,可用putty打開兩個com port進行測試是否可互傳訊息。


2023年4月21日 星期五

[Windows] 開機執行的兩種方法

啟動資料夾

  1. 按 Windows + R,打開執行視窗
  2. 輸入 shell:startup,執行後就會開啟啟動資料夾
  3. 放入開機要執行的程式或 batch檔案


工作排程器

  1. 按 Windows + R,打開執行視窗
  2. 輸入 taskschd.msc,執行後就會開啟工作排程器
  3. 點擊建立基本工作,跳出視窗後輸入名稱及描述
  4. 選擇在電腦啟動時執行
  5. 選擇啟動程式
  6. 輸入要執行的程式路徑,也可以輸入程式的參數要切換的工作目錄,再點選完成
  7. 確認完資訊後再點選完成,Windows的排程工作就能建好了

2023年2月15日 星期三

Beyond BIOS Note - CH6 UEFI Console Service


Never test for an error condition you don't know how to handle.
- Steinbach's Guideline for Systems Programming

UEFI console 主要由兩個 protocol組成:

  • Simple Text Input Protocol (Simple Text Input Ex Protocol)
  • Simple Text Output Protocol

EFI System Table 幾個與 console相關的項目:

  • ConsoleInHandle
  • ConIn
  • Console input device的 handle,此 handle必須 support Simple Text Input Protocol 及 Simple Text Input Ex Protocol,ConIn 則為指向此 Simple Text Input Protocol 的指標。

  • ConsoleOutHandle
  • ConOut
  • Console output device的 handle,此 handle必須 support Simple Text Output Protocol ,ConOut 則為指向此 Simple Text Output Protocol的指標。

  • StandardErrorHandle
  • StdErr
  • Standard error console device的 handle,此 handle必須 support Simple Text Output Protocol ,StdErr則為指向此 Simple Text Output Protocol的指標。


與 console相關的 UEFI global variable:

  • ConIn
  • 預設 console input device的 device path

  • ConInDev
  • 所有可能的 console input device的 device path

  • ConOut
  • 預設 console output device的 device path

  • ConOutDev
  • 所有可能的 console output device的 device path

  • ErrOut
  • 預設 error console的 device path

  • ErrOutDev
  • 所有可能的 error console的 device path


Simple Text Input Protocol

  • Reset
  • Reset input device硬體

  • ReadKeyStroke
  • 讀取按鍵輸入

  • WaitForKey
  • 等待按鍵輸入


Simple Text Input Ex Protocol

  • ReadKeyStrokeEx
  • 比起 ReadKeyStroke能讀取更多種按鍵輸入

  • Key Registration Capabilities
  • 讓使用者可以註冊或取消註冊組合按鍵所觸發的 notification function

  • SetState
  • 設定 input device的狀態。EX:Caps Lock actice


Simple Text Output Protocol

  • OutputString
  • 將 Unicode字串輸出到 output device

  • SetAttribute
  • 設定 OutputString()及 ClearScreen()的前景和背景的顏色

  • ClearScreen
  • 清除 output device 的output

  • SetCursorPosition
  • 設定游標的位置


Remote Console Support

透過 Console driver來產生多一層 Text I/O Interface以達到 remote 介面與 UEFI間的
溝通


Console Splitter

Console Splitter來同時支援多個 input及 output console device,透過 hook EFI System
Table的 ConIn/ConOut/StdErr來達成,且ConIn等 UEFI global可以包含多個 active console 的 device path


Network Console

UEFI也提供與網路溝通的能力,主要包含的元件有:

  • Network Interface Identifier
  • 這功能由 UNDI(Universal Network Driver Interface)提供,並負責產生 Simple
    Network Protocol

  • Simple Network Protocol
  • 提供封包層級的網卡操作介面


2022年11月30日 星期三

使用 Windows Terminal透過 SSH 連線到遠端主機

在公司的工作機是使用 Windows筆電,有時候會需要連到遠端 Linux機器,記錄一些會使用
到的指令。

SSH

根據微軟官網,Windows 本身已經內建 SSH client應用程式。


ssh user@machine

透過 ssh連線到遠端的主機,之後會跳出提示輸入密碼。


exit

logout
Connection to machine closed.

退出 ssh連線回到 Windows Terminal。


SCP

SCP是使用 SSH的遠端加密傳輸檔案指令。


scp C:\a.txt user@machine:~/

將本地的 C:\a.txt傳送到遠端 machine的 user目錄中。

scp C:\a.txt user@machine:~/b.txt

將本地的 C:\a.txt傳送到遠端 machine的 user目錄中,並命名成 b.txt。


scp user@machine:~/b.txt C:\

將遠端 machine的 user目錄中 b.txt傳送到本地端的 C:\目錄中。

scp user@machine:~/b.txt C:\c.txt

將遠端 machine的 user目錄中 b.txt傳送到本地端的 C:\目錄中,並命名成 c.txt。


scp -r user@machine:~/test C:\

將遠端 machine的 user目錄中 test目錄遞迴複製傳送到本地端的 C:\ (C:\test)。

scp -r C:\test user@machine:~/

將本地端的 C:\test目錄遞迴複製到遠端的 user目錄中 (~/test)。

2022年11月25日 星期五

[scikit-learn] datasets

最近開始在上 Coursera台大林軒田的 Machine Learning的課程,第二周的內容重點是關於 PLA
(Perceptron Learning Algorithm),於是就想實作關於 PLA的程式碼。

首先是要有一組線性可分的資料,但要手動產生線性可分資料過於麻煩,而 scikit-learn提供
datasets 這個為機器學習使用者所用的資料集合。

以 iris plant dataset為例,其提供了鳶尾花的植物特徵資料:

https://scikit-learn.org/stable/datasets/toy_dataset.html
  • 花萼長度 (sepal length in cm)
  • 花萼寬度 (sepal width in cm)
  • 花瓣長度 (petal length in cm)
  • 花瓣寬度 (petal width in cm)
  • Class:Setosa、Versicolour及Virginica

三個品種的鳶尾花各50組,總共150組資料。透過 load_iris來獲得:

https://scikit-learn.org/stable/modules/generated/sklearn.datasets.load_iris.html

參考scikit-learn提供的範例The Iris Dataset來看其資料分布的情形。可以用來練習線性可分
的情況,也能練習在線性不可分下中使用 Pocket Algorithm。

用 matplotlib畫出其資料分布圖:


2022年10月29日 星期六

[Python] Decorator 裝飾器 (2) - wraps

上篇文章:
[Python] Decorator 裝飾器

在使用 decorator時,會使得原本被包裹的 function 的 attribute資料遺失。

import time

def measuretime(func):

    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print (func.__name__, end - start)
        return result

    return wrapper

@measuretime
def count_down(n):
    '''Counts down from n'''
    while n > 0:
        n -= 1

if __name__ == '__main__':
    print (count_down.__name__)
    print (count_down.__doc__)

Output:

wrapper
None

可使用 functools的 decorator wraps來避免這種情況:

import time
from functools import wraps

def measuretime(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print (func.__name__, end - start)
        return result

    return wrapper

@measuretime
def count_down(n):
    '''Counts down from n'''
    while n > 0:
        n -= 1

if __name__ == '__main__':
    print (count_down.__name__)
    print (count_down.__doc__)

Output:

count_down
Counts down from n

Unwrapping

wraps提供了另一個有用的功能,可以使已經套用過 decorator的 function回復成套用前的
function。透過 __wrapped__這個屬性來使用原本的 function。

import time
from functools import wraps

def measuretime(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print (func.__name__, end - start)
        return result

    return wrapper

@measuretime
def count_down(n):
    '''Counts down from n'''
    print (f'Counts down from {n}')
    while n > 0:
        n -= 1

if __name__ == '__main__':
    count_down(500000)
    org_count_down = count_down.__wrapped__
    org_count_down(500000)

Output:

Counts down from 500000
count_down 0.021966218948364258
Counts down from 500000