# AIoT班上課紀錄 Part I
## AIoT班上課紀錄 Part II網址
https://hackmd.io/@aaronlife/uch-aiot-2024-2
## 2024-07-03筆記
https://hackmd.io/@aaronlife/uch-aiot-2024-3
## 2024-07-01
#### 多執行緒
```python=
import time
import threading
def func1():
print('Function 1 starting...')
for i in range(1, 4):
time.sleep(1)
print(f'1-{i}')
event.set()
event1.wait()
event1.clear()
lock.acquire()
print('Function 1 end')
lock.release()
def func2():
print('Function 2 starting...')
for i in range(1, 4):
event.wait()
event.clear()
time.sleep(1)
print(f'2-{i}')
event2.set()
lock.acquire()
print('Function 2 end')
lock.release()
def func3():
print('Function 3 starting...')
for i in range(1, 4):
event2.wait()
event2.clear()
time.sleep(1)
print(f'3-{i}')
event1.set()
lock.acquire()
print('Function 3 end')
lock.release()
# 建立Lock物件
lock = threading.Lock()
# 建立Event物件
event = threading.Event() # set(), wait(), clear()
event1 = threading.Event() # set(), wait(), clear()
event2 = threading.Event() # set(), wait(), clear()
# 建立執行緒
f1 = threading.Thread(target=func1)
f2 = threading.Thread(target=func2)
f3 = threading.Thread(target=func3)
print(time.strftime('%H:%M:%S'))
# func1()
# func2()
# func3()
f1.start() # 啟動func1執行緒
f2.start() # 啟動func2執行緒
f3.start() # 啟動func3執行緒
f1.join()
f2.join()
f3.join()
print(time.strftime('%H:%M:%S'))
event = threading.Event()
```
## 2024-06-28
#### google搜尋自動化
https://hackmd.io/@aaronlife/python-topic-crawler
```
from selenium.webdriver.common.keys import Keys
```
#### 微笑單車登入
```python=
from selenium import webdriver
from bs4 import BeautifulSoup
from selenium.webdriver.common.by import By
import time
# 初始化Chrome瀏覽器驅動程式
driver = webdriver.Chrome()
# 載入網頁時要等待的時間(秒)
driver.implicitly_wait(10)
# 用Chrome瀏覽器打開網頁
driver.get('https://www.youbike.com.tw/region/main/login/')
# 印出網頁標題
print(driver.title)
# 解析資料
confirm_btn = driver.find_element(By.LINK_TEXT, '確定')
confirm_btn.click()
time.sleep(2)
phone_input = driver.find_element(By.NAME, 'phone')
phone_input.send_keys('0987654321')
time.sleep(2)
password_input = driver.find_element(By.NAME, 'password')
password_input.send_keys('qW123456')
time.sleep(2)
login_btn = driver.find_element(By.LINK_TEXT, '登入')
login_btn.click()
time.sleep(20)
```
## Selenium資料定位
Selenium有兩個系列的資料定位函式:
- `find_element()`: 用來取得網頁中的第一個定位到的HTML元素。
- `find_elements()`: (名稱中多了一個s),用來取得所有網頁中定位到的元素。
這兩個函式都可以使用下面方式來定位元素:
| 名稱 | 說明 |
| --------------------- | ---------------------------- |
| `"id"` | 使用id屬性值來定位元素 |
| `"name"` | 使用name屬性值來定位元素 |
| `"xpath"` | 使用XPath表達式來定位元素 |
| `"link text"` | 使用超連結文字來定位元素 |
| `"partial link text"` | 使用部分超連結文字來定位元素 |
| `"tag name"` | 使用標籤名稱來定位元素 |
| `"class name"` | 使用class屬性值來定位元素 |
| `"css selector"` | 使用CSS選擇器來定位元素 |
```
ID = "id"
XPATH = "xpath"
LINK_TEXT = "link text"
PARTIAL_LINK_TEXT = "partial link text"
NAME = "name"
TAG_NAME = "tag name"
CLASS_NAME = "class name"
CSS_SELECTOR = "css selector"
```
#### Selenium動作函式:
| 名稱 | 說明 |
| ------------------- | ---------------------- |
| `click()` | 點擊元素 |
| `click_and_hold()` | 在元素上按住滑鼠左鍵 |
| `context_click()` | 在元素上按住滑鼠右鍵 |
| `double_click()` | 點擊兩次元素 |
| `move_to_element()` | 移動滑鼠游標到元素中間 |
| `key_up()` | 放開鍵盤的按鍵 |
| `key_down()` | 按下鍵盤的按鍵 |
| `perform()` | 執行所有儲存的動作 |
| `send_keys()` | 送出按鍵到元素 |
| `release()` | 在元素上鬆開滑鼠按鍵 |
#### 執行JavaScript程式碼
##### 使用 Selenium 滾動網頁捲軸(scrollBar)
```
driver.execute_script('window.scrollBy(0,1000)')
```
**說明:**
scrollBy(x,y)中,x為必須參數,表示向右滾動的像素值;y也為必須參數,表示向下滾動的像素值
```
driver.execute_script('window.scrollTo(0,1000)')
```
**說明:**
scrollTo(x,y) 中,x為必要參數,表示要在視窗顯示區左上角顯示的x坐標;y也為必要參數,表示要在視窗顯示區左上角顯示的y坐標
##### 捲軸拉到底
```
driver.execute_script('window.scrollTo(0,document.body.scrollHeight)')
```
或
```
driver.execute_script('window.scrollTo(0,document.documentElement.scrollHeight)')
```
#### send_key()常用的按鍵代碼
`ENTER` `SHIFT` `LEFT_SHIFT` `CONTROL` `LEFT_CONTROL` `ALT` `LEFT_ALT` `SPACE`
#### Selenium
```python=
from selenium import webdriver
from bs4 import BeautifulSoup
from selenium.webdriver.common.by import By
# 初始化Chrome瀏覽器驅動程式
driver = webdriver.Chrome()
# 載入網頁時要等待的時間(秒)
driver.implicitly_wait(10)
# 用Chrome瀏覽器打開網頁
driver.get('https://rate.bot.com.tw/xrt?Lang=zh-TW')
# 印出網頁標題
print(driver.title)
# 印出網頁
print(driver.page_source)
# 解析資料
download_csv = driver.find_element(By.LINK_TEXT, '下載 Excel (CSV) 檔')
print(download_csv.tag_name)
print(download_csv.get_attribute('href'))
download_csv.click()
import time
time.sleep(5)
# .....
```
## 2024-06-27
#### BeautifulSoup講義
https://hackmd.io/@aaronlife/python-topic-beautifulsoup
#### 台灣銀行匯率
```python=
import requests
from bs4 import BeautifulSoup
import csv
import time
# 台灣銀行匯率網址
# url = 'https://rate.bot.com.tw/xrt?Lang=zh-TW'
# response = requests.get(url)
# with open('rate.html', 'w', encoding='utf-8') as file:
# file.write(response.text)
result = []
with open('rate.html', 'r', encoding='utf-8') as file:
data = file.read(135 * 1024 * 1000)
soup = BeautifulSoup(data, 'html.parser')
# print(soup.html.body.label)
trs = soup.tbody.find_all('tr')
for i in trs:
rate = []
print(i.td.div.find_all('div')[1].text.strip()) # 幣別
rate.append(i.td.div.find_all('div')[1].text.strip())
# flag = i.find(class_='rate-content-cash')
# flag = i.find(title='幣別國旗')
q = {'data-table': '本行現金買入'}
flag = i.find(attrs=q)
print(f' - 本行現金買入: {flag.text}')
rate.append(flag.text)
q = {'data-table': '本行現金賣出'}
flag = i.find(attrs=q)
print(f' - 本行現金賣出: {flag.text}')
rate.append(flag.text)
q = {'data-table': '本行即期買入'}
flag = i.find(attrs=q)
print(f' - 本行即期買入: {flag.text.strip()}')
rate.append(flag.text.strip())
q = {'data-table': '本行即期賣出'}
flag = i.find(attrs=q)
print(f' - 本行即期賣出: {flag.text.strip()}')
rate.append(flag.text.strip())
result.append(rate)
print(result)
filename = time.strftime('%Y%m%d_%H%M%S.csv')
with open(filename, 'w', encoding='utf-8', newline='') as file:
writer = csv.writer(file)
writer.writerows(result)
```
### HTML語法規則
- 規則1:所有的HTML元素都有「開始」標籤和「結束」標籤,而該元素的內容放在兩個標籤內,例如:
```
<開始標籤>元素內容</結束標籤>
```
> 雖然瀏覽器有時很聰明,當你沒有加上結束標籤時仍然可以正常顯示,但仍請保持正確的標籤規則。
- 規則二:如果該標籤內不需要元素內容,則稱為空標籤,可以將「開始」標籤與「結束」標籤簡寫為:
```
<空標籤 />
```
- 規則三:巢狀標籤,HTML元素內可以標含其它元素,但必須將其完整包圍,也就是不可以將被包圍的元素的「結束」標籤放到包圍該元素的「結束」標籤下面,例如:
#### 正確:
```
<article>
<h1>文章</h1>
</article>
```
#### 錯誤:
```
<article>
<h1>文章
</article>
</h1>
```
- 規則四:屬性,有些標籤需要透過屬性來設定其特殊功能,例如: `<a>`標籤為超連結標籤,需要透過`href`屬性來設定要前往的目的地,範例:
```
<a href="https://www.google.com">前往Google首頁</a>
```
- 規則五:標籤名稱使用小寫英文,雖然這個規則不是強制的,也就是說HTML元素名稱並不會區分大小寫,<P>和<p>都是一樣的意義,但W3C仍建議HTML內全部使用英文小寫來作為標籤名稱,因為小寫英文字母會比大寫來的容易閱讀。
## HTML5元素
### HTML5新增的元素
HTML5新增了許多特定的語意標籤以支援網頁版面設計,用來取代了不具意義的div、span標籤,網頁設計師利用這些與義標籤建立具有明確架構定義的網頁,讓整個HTML的結構更有意義並且更容易被理解。
![img](http://www.aaronlife.com/v1/teaching/images/img_sem_elements.gif)使用語意標籤來建立網頁版面(圖片來源:W3School)
#### header
網頁頁面的頂部,通常用來放置網站的主要標題、圖片與LOGO等主要的資訊。
#### hgroup
定義著一個區段或一份文件的標題,該元素是用來對 h1 到 h6 的標題群組化。其中最大的標題為區段的主要標題,其它則屬於次要標題。當標題擁有多個層級時,這個元素會被用來對 h1-h6 元素的集合做群組化。
#### nav
通常為網站的主要功能選單。
#### article
網頁中的一個內容區塊,是獨立且完整的內容,在一個網頁中可以有很多個。
#### aside
主要內容之外的其他內容,可以為網站的側邊欄。
#### section
用於內容等等段落的區分,在一個內容中可以有許多個。
#### figure & figcaption
figure用來作為一段獨立的引用區域,用來在網頁內容旁說明或展示獨立的內容,而figcaption用來作為設定該區域的標題。
#### footer
網頁下方,用來顯示網站相關資訊、著作權等等。
#### mark
文字高亮。
> - 完整的新增元素,可以參考W3C網站:https://www.w3schools.com/html/html5_new_elements.asp
> - 讓IE8以前(包含)IE8的瀏覽器支援新元素:https://www.w3schools.com/html/html5_browsers.asp
> - W3C建議的將舊網頁改為使用語意標籤:https://www.w3schools.com/html/html5_migration.asp
### HTML5保留的元素
| 標籤 | 說明 |
| :----------- | :------------------------------------------------- |
| \<!--..--> | HTML文件註解 |
| \<!DCOTYPE> | 定義HTML文件類型 |
| \<head> | 定義與網頁文件有關之資訊,其內容不會顯示在瀏覽器上 |
| \<body> | HTML主要內容最外層的元素 |
| \<abbr> | 定義縮寫文字 |
| \<address> | 定義內容為地址 |
| \<area> | 定義帶有可點擊影像地圖區域 |
| \<base> | 定義網頁中所URL的連接基準 |
| \<bdo> | 定義文字顯示方向 |
| \<blockquote> | 定義額外註解或較長的引文 |
| \<br> | 換行符號 |
| \<button> | 定義一個按鈕 |
| \<caption> | 定義一個表格標題 |
| \<cite> | 定義著作的標題 |
| \<dd> | 在列表中定義條目的定義 |
| \<div> | 定義網頁內的一個區塊(自動換行) |
| \<span> | 定義網頁內的一個區塊(不換行) |
| \<dl> | 用於一個列表的定義 |
| \<dt> | 用於一個項目的定義 |
| \<em> | 用於強調文字 |
| \<form> | 建立表單 |
| \<h1>~\<h6> | 定義標題文字,有1~6個等級 |
| \<input> | 定義一個可輸入的區域 |
| \<ins> | 定義為插入的文字 |
| \<del> | 定義為刪除的文字 |
| \<map> | 定義一個影像地圖的範圍 |
| \<object> | 定義一個嵌入物件 |
| \<ol> | 定義一個有數字順序的清單 |
| \<ul> | 定義一個無順序的清單 |
| \<li> | 定義一個表單的項目 |
| \<p> | 定義一個段落 |
| \<pre> | 定義一段非HTML格式的文字區塊 |
| \<select> | 定義一個下拉式選單 |
| \<textarea> | 定義一個文字輸入區域 |
| \<var> | 定義一個變數 |
> 完整HTML元素:https://www.w3schools.com/tags/
### HTML5保留下來但改變用法的元素
| 標籤 | 說明 | HTML4的用法 | HTML5的用法 |
| -------- | ---------------------------------------------- | ------------------------ | ------------------------------------------------------------ |
| \<a> | 定義內容為一個超連結 | 須有href=”#”屬性才能連結 | 該標籤永遠表示超連結,只是當沒有href的情況下,就只是一個佔位符號 |
| \<b> | 定義文章區塊以外的內容,通常用於內容相關的邊欄 | 表現粗體 | 除了表現粗體,其他特別但不太重要的內容,想要特別強調時 |
| \<hr> | 定義為音效內容 | 做為水平分隔線 | 更換段落主題時使用的水平分隔線 |
| \<i> | 定義網頁上的繪圖區塊 | 表現斜體 | 除了表現斜體,無重要資料的其他內容,但想要另外標示時使用 |
| \<menu> | 定義一個指令按鈕 | - | 定義複雜的選單或表單結構 |
| \<small> | 定義一個下拉式選單 | 表現較小字體 | 備註或是其他法律特殊字體需要小字時使用 |
| \<strong> | 定義一個元件的細項 | 表現較大字體 | 除了表現較大字體,也可標示重要資訊 |
### HTML5移除的元素
| 移除的元素 | 替代元素 |
| :--------- | :----------------- |
| \<acronym> | \<abbr> |
| \<applet> | \<object> |
| \<basefont> | CSS |
| \<big> | CSS |
| \<center> | CSS |
| \<dir> | \<ul> |
| \<font> | CSS |
| \<frame> | 無 |
| \<frameset> | 無 |
| \<noframes> | 無 |
| \<strike> | CSS, \<s>, or \<del> |
| \<tt> | CSS |
> - 資料來源為W3C網站:https://www.w3schools.com/html/html5_intro.asp
> - 雖然瀏覽器大都繼續支援這些被移除的標籤,但作一個為良好的HTML5網頁,請盡量不要再使用它們。
#### 一個使用HTML5語意標籤的範例:
```html=
<!DOCTYPE html>
<html>
<head>
<title>HTML5 網頁範例</title>
</head>
<body>
<header>
<hgroup>
<h1><a href="#">網站主標題</a></h1>
<h2><a href="#">網站次標題</a></h2>
</hgroup>
<p>其它說明文字</p>
</header>
<nav>
<ul>
<li><a href="index.html">首頁</li>
<li><a href="life.html">生活心得</a></li>
<li><a href="travel.html">旅遊新知</a></li>
<li><a href="about.html">關於我</a></li>
</ul>
</nav>
<section>
<article>
<header>
<h3><a href="#">內容標題1</a></h3>
</header>
<section>
<p>內容段落1</p>
<p>內容段落2</p>
</section>
</article>
<article>
<header>
<h3><a href="#">內容標題2</a></h3>
</header>
<section>
<p>內容段落1</p>
<p>內容段落2</p>
<p>內容段落3</p>
<p>內容段落4</p>
</section>
</article>
</section>
<aside>
<h2><a href="#">aside</a></h2>
<p>補充資料/子選單</p>
</aside>
<footer>版權宣告</footer>
</body>
</html>
```
## HTML結構
#### 文件類型宣告(DOCTYPE)
HTML檔案第一個元素就是「文件類型宣告(doctype)」,doctype告訴瀏覽器這個頁面使用哪一版的HTML,對HTML 5來說,doctype為:
```
<!DOCTYPE html>
```
這個元素較為特別,不需要結束標籤,也是唯一一個不需要的。
#### HTML結構
接著doctype後面則為HTML的全部內容,劃分為兩個部分:<head>與<body>,這兩個部分被<html>元素包圍:
```
<!DOCYPTE html>
<html>
<head>
...這裡是head元素內的內容,用來放置該HTML文件的資訊或設定,不會顯示在瀏覽器上...
</head>
<body>
...這裡是body元素內的內容,所有顯示在網頁上的資料都放在body裡面...
</body>
</html>
```
#### html範例:
```html=
<!DOCTYPE html>
<html>
<head>
<title>我的網站</title>
<style>
li, p {
color: greenyellow;
font-family: 'Courier New', Courier, monospace;
font-size: 1.5em;
}
#test {
color: royalblue;
}
#test2 {
font-size: 2em;
text-decoration: none;
color: aquamarine;
}
#test2:hover {
color: brown;
}
.my-style {
color: burlywood;
background-color: blue;
font-family: 'Courier New', Courier, monospace;
}
</style>
</head>
<body>
<h1 style="color:darkorange;font-size: 3em;">內容22<br />
22222</h1>
<h6>內容2222222</h6>
<p id="test">這是<strong>文章</strong>段落</p>
<a id="test2" href="https://www.yahoo.com.tw">點我前往Yahoo</a>
<br/>
<img style="width: 49.5%;" src="https://d1grca2t3zpuug.cloudfront.net/2023/10/sendaiginzan.jpg" />
<img style="width: 49.5%;" src="https://d1grca2t3zpuug.cloudfront.net/2023/10/sendaiginzan.jpg" />
<ul>
<li>這是清單1</li>
<li>這是清單2</li>
<li>這是清單3</li>
</ul>
<ol>
<li>這是清單1</li>
<li>這是清單2</li>
<li>這是清單3</li>
</ol>
<table style="width: 50%;border: 1px solid rebeccapurple;margin: 0;">
<tr>
<td>欄位</td>
<td class="my-style">欄位</td>
<td>欄位</td>
<td class="my-style">欄位</td>
</tr>
<tr>
<td>欄位1</td>
<td class="my-style">欄位2</td>
<td>欄位3</td>
<td>欄位4</td>
</tr>
</table>
<article>
<header>
<h2>文章標題</h2>
<h4>作者: Aaron</h4>
</header>
<p>文章內容文章內容文章內容文章內文章內容文章內容文章內容文章內文章內容文章內容文章內容文章內文章內容文章內容文章內容文章內文章內容文章內容文章內容文章內文章內容文章內容文章內容文章內容文章內容文章內容文章內容文章內容文章內容文章內容</p>
<p>文章內容文章內容文章內容文章內容文章內容文章內容文章內容文章內容文章內容文章內容</p>
<p>文章內容文章內容文章內容文章內容文章內容文章內容文章內容文章內容文章內容文章內容</p>
</article>
</body>
</html>
```
## 2024-06-26
#### 多型
```python=
class Triangle:
def __init__(self, level):
self.__level = level
def show(self):
for i in range(self.__level):
for j in range(i + 1):
print('*', end='')
print()
class RTriangle:
def __init__(self, level):
self.__level = level
def show(self):
for i in range(0, -self.__level, -1):
for j in range(self.__level + i):
print('*', end='')
print()
class Rectangle:
def __init__(self, level):
self.__level = level
def show(self):
for i in range(self.__level):
for j in range(self.__level):
print('*', end='')
print()
class Line:
def __init__(self, level):
self.__level = level
def show(self):
for i in range(self.__level):
print('**')
graph = []
graph.append(Triangle(5))
graph.append(Rectangle(3))
graph.append(RTriangle(5))
graph.append(Line(5))
for obj in graph: # 多型
obj.show()
```
```python=
class Car:
def __init__(self, color): # 建構式
self.__color = color
self.__gas = 0
self.color = color
def run(self):
print('車子在跑')
def show(self):
print(f'我是{self.__color}車子')
class Truck(Car): # Car類別是Truck的父類別,Truck類別繼承了Car類別所有屬性和方法,Truck是Car的子類別
def __init__(self, color):
# self.__color = color
super().__init__(color)
# override父類別的方法
def show(self):
print(f'我是{self.color}卡車')
super().show() # 呼叫父類別的同名方法
t = Truck('黑色')
t.run()
t.show()
```
#### 複寫運算子
參考: https://www.programiz.com/python-programming/operator-overloading
```python=
class Car:
def __init__(self, color):
self.__color = color
self.gas = 0
print('Hi')
def show(self, x, y):
print(f'顏色: {self.__color}', x, y)
def __str__(self):
return f'顏色: {self.__color}'
def __add__(self, item):
return self.__color + item.__color
def __contains__(self, item):
return False
a = Car('紅色') # 以Car類別來件立一個實體Car物件
a.show(1, 2)
b = Car('黃色')
b.show(3, 4)
# print(a.color)
# print(b.color)
print(a)
print(a+b)
print(a in b)
```
#### 特殊方法
```python=
class Car:
def __init__(self, color):
self.__color = color
self.gas = 0
print('Hi')
def show(self, x, y):
print(f'顏色: {self.__color}', x, y)
def __str__(self):
return f'顏色: {self.__color}'
a = Car('紅色') # 以Car類別來件立一個實體Car物件
a.show(1, 2)
b = Car('黃色')
b.show(3, 4)
# print(a.color)
# print(b.color)
print(a)
```
####
```python=
class Car:
def show(self, x, y):
print(f'顏色: {self.color}', x, y)
self.__gas = 9
# self.__callme()
def callme(self): # 私有方法
print('Please call me')
print(self.__gas)
color = '黑色'
a = Car() # 以Car類別來件立一個實體Car物件
a.color = '紅色'
a.show(1, 2)
b = Car()
b.color = '黃色'
b.show(3, 4)
print(color)
print(a.color)
print(b.color)
# a.__callme()
a.__gas = 999
print(a.__gas)
a.callme()
```
#### 方法
```python=
class Car:
def show(self, x, y):
print(f'顏色: {self.color}', x, y)
color = '黑色'
a = Car() # 以Car類別來件立一個實體Car物件
a.color = '紅色'
a.show(1, 2)
b = Car()
b.color = '黃色'
b.show(3, 4)
print(color)
print(a.color)
print(b.color)
```
#### 類別
```python=
class Car:
pass
color = '黑色'
a = Car() # 以Car類別來件立一個實體Car物件
a.color = '紅色'
b = Car()
b.color = '黃色'
print(color)
print(a.color)
print(b.color)
```
#### 連續輸入數字
```python=
total = 0
# while True:
# user = input('請輸入數字(quit=離開): ')
# if user == 'quit':
# break
# else:
# total += int(user)
def give_me_number():
while True:
user = input('請輸入數字(quit=離開): ')
if user == 'quit':
break
else:
yield int(user)
for i in give_me_number():
total += i
print(f'總合為: {total}')
```
#### yield with for-in
```python=
def foo():
yield 5
yield 6
yield 7
yield 8
yield 9
g = foo()
a = [11, 22, 33]
b = (i for i in a)
print(next(b))
print(next(b))
print(next(b))
```
#### yield
```python=
def foo():
print('start...')
a = yield 9 # 函式會變成產生器
print('part 2', a)
yield 10
print('part 3')
yield 10
g = foo()
next(g)
a = g.send('Hi') # 產生器的函式只能執行一次
print(a)
b = next(g)
print(b)
```
```python=
import random
# 裝飾器 decorator
def b(func):
def c(x, y):
a = func(x, y)
with open('random.txt', 'w', encoding='utf-8') as file:
file.write(str(a))
return a
return c
# b = {'a': 'b', 'c': 'd'}
for k, v in vars(random).items():
if k == 'randint':
vars(random)[k] = b(v) # 手動裝飾器
a = random.randint(1, 9999)
print(a)
```
## 2024-06-25
#### AOP有參數和return
```python=
def b(func):
def c(x, y):
print('開始前執行')
r = func(x, y)
print('結束後執行')
return r
return c
@b
def a(x, y):
print('很厲害的事情')
return x + y
result = a(2, 3) # 其實就是變成呼叫c()函式
print(result)
```
#### AOP
```python=
def b(func):
def c():
print('開始前執行')
func()
print('結束後執行')
return c
@b
def a():
print('很厲害的事情')
return 999
```
#### 全校平均
```python=
school = [43, 52, 26, 33, 91, 5, 11]
a = [78, 63, 45, 88, 37, 92]
from functools import reduce
# 找出班級最低分
min = reduce(lambda x, y: y if x > y else x, a)
print(f'最低分: {min}')
total = reduce(lambda x, y: x + y, school)
avg = total / len(school)
print(f'全校平均: {avg:2.2f}')
if avg > min:
print('該班級最低分低於全校平均')
elif avg < min:
print('該班級最低分高於全校平均')
else:
print('該班級最低分等於全校平均')
```
#### 數字每個位數相乘(單行寫法)
```python=
from functools import reduce
print(reduce(lambda x, y: x*y,list(map(lambda x: int(x), list(input())))))
```
#### 數字每個位數相乘(平易近人寫法)
```
user = input()
user = list(user)
data = []
for i in user:
data.append(int(i))
result = 1
for j in data:
result *= j
print(result)
```
#### 1A2B
```python=
import random
a = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
answer = random.sample(a, 4)
answer = answer[0] + answer[1] + answer[2] + answer[3]
# answer = ''.join(answer)
print(f'答案: {answer}')
count = 0 # 存次數
while True:
user = input('請猜四位數數字(數字不可重複): ')
count += 1
# 判斷輸入的文字是不是數字
try:
int(user)
except ValueError:
print('只能輸入數字,請重新輸入')
continue
# 輸入的數字是否為四位數
if len(user) != 4:
print('只能輸入四位數')
continue
# 輸入的數字是否重複
if len(set(user)) != 4:
print('輸入的數字不可重複')
continue
if answer == user:
print(f'猜對了,總共猜了{count}次')
break
# 判斷幾個A
how_many_A = 0
if answer[0] == user[0]:
how_many_A += 1
if answer[1] == user[1]:
how_many_A += 1
if answer[2] == user[2]:
how_many_A += 1
if answer[3] == user[3]:
how_many_A += 1
# 判斷幾個B
how_many_B = 0
if user[0] in answer and user[0] != answer[0]:
how_many_B += 1
if user[1] in answer and user[1] != answer[1]:
how_many_B += 1
if user[2] in answer and user[2] != answer[2]:
how_many_B += 1
if user[3] in answer and user[3] != answer[3]:
how_many_B += 1
print(f'{how_many_A}A{how_many_B}B')
```
#### 例外處理
```python=
print('1')
try:
[1, 2, 3][3]
int('a')
except ValueError:
print('轉型錯誤')
except IndexError:
print('索引錯誤')
print('2')
```
#### 套件
```python=
# import aaron.bluemonday
from aaron.bluemonday import showme as showshow
from busytuesday import showme
import aaron.bluemonday as a
# aaron.bluemonday.showme('andy', 13)
showme('apple', 40)
showshow('apple', 40)
a.showme()
```
> **備註:**
> 套件下可以建立`__init__.py`來做初始化動作
#### 模組
##### busytuesday.py
```python=
def plus(a, b):
return a + b
def min(a, b):
return a - b
def mux(a, b):
return a * b
def div(a, b):
return a / b
owner = 'aaron'
if __name__ == '__main__':
result1 = plus(1, 2)
print(result1)
```
##### employee.py
```python=
# import busytuesday
# r = busytuesday.mux(4, 5)
# print('同事的結果:', r)
# print('同事的結果:', busytuesday.owner)
from busytuesday import div
# 衝突
# def div():
# print('同名函式')
result = div(6, 3)
print(result)
```
## 2024-06-24
#### 不定長度參數、指定參數
```python=
# 預設參數
def showme(name, age, phone='無資料', addr='無資料'):
print(f'姓名: {name}, 年紀: {age}, 電話: {phone}, 地址: {addr}')
showme('aaron', 13)
```
```python=
def plus(*a):
for i in a:
print(i, end=' ')
return sum(a)
print(plus(1, 2, 3, 4))
def showme(name, age, phone):
print(f'姓名: {name}, 年紀: {age}, 電話: {phone}')
# 指定參數
showme(age=34, name='aaron', phone='0987654321')
# 第二種不定長度參數
def dosomething(**argv):
print(argv)
dosomething(a=1, aaron=2, ok=3, w=4, aaa=5)
```
#### reduce
##### 最高分在哪個班級
```python=
from functools import reduce
a = {'甲': (31, 56, 23), '乙': (88, 92, 48), '丙': (100, 33, 72)}
# 找出班級最高分
def dosomething1(x, y):
return x if x > y else y
def dosomething2(x, y):
# 找出x班級最高分
x1 = reduce(dosomething1, a[x])
# 找出y班級最高分
y1 = reduce(dosomething1, a[y])
# 比較兩個班級的最高分
if x1 > y1:
return x # 回傳班級名稱
else:
return y # 回傳班級名稱
print(reduce(dosomething2, a))
```
##### 誰年紀最小
```python=
from functools import reduce
a = {'aaron': 13, 'andy': 45, 'apple': 22}
def dosomething(x, y):
if a[x] > a[y]:
return y
else:
return x
print(reduce(dosomething, a))
```
```python=
from functools import reduce
a = [23, 47, 98, 15, 62]
def dosomething(x, y):
if x > y:
return y
else:
return x
print(reduce(dosomething, a))
```
```python=
from functools import reduce
a = [1, 2, 3, 4, 5, 6]
def dosomething(x, y):
return x + y
print(reduce(dosomething, a))
```
#### map
```python=
a = [13, 67, 34, 32, 98]
def dosomething(x):
if x < 60:
return x + 10
else:
return x
print(list(map(dosomething, a)))
```
##### lambda寫法
```python=
print(list(map(lambda x: x + 10 if x < 60 else x, a)))
```
```python=
# map
a = [13, 67, 34, 32, 98]
def dosomething(x):
return x + 10
result = list(map(dosomething, a))
print(result)
```
#### filter
```python=
# filter
a = [3, '你', 99, 'abc', 87, 'X']
result = filter(lambda x: isinstance(x, int), a)
print(list(result))
```
####
```python=
# filter
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 50, 70, 80]
result = filter(lambda x: x >= 60, a)
print(list(result))
```
#### 高階函式
```python=
def math(a, b, f):
return f(a, b)
def plus(a, b):
return a + b
def mux(a, b):
return a * b
a = math(2, 3, plus)
print(a)
a = math(2, 3, mux)
print(a)
```
#### 一級函式
```python=
# def a():
# print('a')
# print('b')
# print(type(a))
# sum = lambda a, b: a + b
# sum = a()
# print(sum)
# print(sum([1, 2, 3]))
# sum()
a = (lambda a, b: a + b)(1, 2)
print(a)
```
#### lambda
```python=
# def plus(a, b):
# return a + b
plus = lambda a, b: a + b
print(plus(1, 2))
```
####
```python=
def kill_odd(data):
# result = []
# for i in data:
# if i % 2 == 0:
# result.append(i)
# return result
return [i for i in data if i % 2 == 0]
print(kill_odd([1, 2, 3, 4, 5, 6, 7, 8, 9]))
```
#### 回傳值
```python=
def a():
return 'aaron'
b = a()
print(b)
def plus(a, b):
# print(f'{a} + {b} = {a + b}')
return a + b
c = plus(4, 5)
print(f'總和: {c}')
```
#### 函式
```python=
def a():
print('a')
print('b')
print('c')
a() # 函式呼叫
a() # 函式呼叫
a() # 函式呼叫
def plus(a, b): # 函式的參數式函式自己的私有變數(區域變數)
if not isinstance(a, int):
print('參數a不是數字')
elif not isinstance(b, int):
print('參數b不是數字')
# a = 5
# b = 6
else:
print(f'{a} + {b} = {a + b}')
plus(1, 3) # must
plus(13, 43) # must
plus(3, 's') # must
```
## 2024-06-14
#### 函式
```python=
def my_func():
print('1')
print('2')
print('3')
my_func() # 涵式呼叫
my_func()
a = 5
def plus(a, b):
# a = 1
# b = 2
print(f'加總後為: {a + b}')
plus(3, 4)
plus(5, 6)
plus(99, 66)
print(a)
```
#### dict
```python=
a = {'d': 8, 1: 99, True: 88, 33: 'OK', 0: 'aaron', False: 'andy', frozenset({3, 4}): 'hh'}
# a[4] = 99
# a[4] = 88
# del a[4]
# a[1] = 77
# print(a[True])
print(a)
for key in a:
print(key, a[key])
for value in a.values():
print(value)
# a = ['aaron', 'andy', 'apple']
# b = [44, 77, 9]
# print(dict(zip(a, b)))
print(a[ frozenset({3, 4}) ])
b = {4: 5}
a.update(b)
print(a)
```
#### 算參加人數
```python=
a = ['aaron', 'andy', 'andy', 'apple', 'abner', 'aaron']
print(len(set(a)))
```
#### 交集 聯集 差集 對稱差集
```python=
employee1 = {'英文', '日語', '粵語', '台語'}
employee2 = {'法文', '德語', '中文', '日語', '台語'}
print(f'兩個人都會的語言: {employee1 & employee2}')
print(f'兩個人總共會的語言: {employee1 | employee2}')
print(f'只有員工1會的語言: {employee1 - employee2}')
print(f'只有員工2會的語言: {employee2 - employee1}')
print(f'只有一個人會的語言: {employee1 ^ employee2}')
```
#### set
```python=
a = {1, 2, 3}
print(type(a))
a = set() # 建立空的set
print(type(a))
# 新增
a.add('d')
a.add(5)
a.add(5)
a.add(5)
print(a)
# 讀取
for i in a:
print(i)
# 修改
# 刪除
a.remove(5)
print(a)
```
#### generator
```python=
a = (n for n in range(10))
# generaotr
print(type(a))
for i in a:
print('1st:', i)
for i in a:
print('2nd:', i)
```
#### zip
```python=
a = ['aaron', 'andy', 'alan', 'apple']
b = [66, 77, 88, 99]
c = zip(a, b)
print(list(c))
```
#### Tuple打包跟解包
```python=
a = 1, 2, 3, # 打包
print(a, type(a))
c, d, e = a # 解包
e, *f = a
print('e:', e)
print('f:', f)
a = 1, 2, 3, 4, 5
b, *c, d = a
print(b)
print(d)
print(c)
```
#### 刪除list裡面全部指定的元素
```python=
a = ['aaron', 'apple', 'alan', 'aaron']
# a.remove('aaron')
while 'aaron' in a:
a.remove('aaron')
print(a)
```
#### 終極密碼
```python=
import random
answer = random.randint(1, 100)
print(f'答案: {answer}')
min = 1
max = 100
count = 0
while True:
user = input(f'請猜 {min} ~ {max} 之間的數字(目前猜了{count}次): ')
count += 1
# error handling
if user.isdigit():
user = int(user)
else:
print('輸入錯誤,只能輸入數字,請重新輸入')
continue
if user < min or user > max:
print(f'輸入錯誤,超出{min}~{max}範圍,請重新輸入')
continue
if user < answer:
min = user + 1
elif user > answer:
max = user - 1
else:
print(f'猜對了,總共猜了{count}次')
break
```
#### 猜數字
```python=
import random
answer = random.randint(1, 10)
print(f'測試用: {answer}')
count = 0 # 紀錄總共猜了幾次
while True:
user = int(input('請猜一個數字: '))
count += 1 # 加一次
if user == answer:
print(f'猜對了,總共猜了{count}次')
break
else:
print(f'猜錯了,已經猜了{count}次')
```
#### while迴圈
```python=
a = 0
while a < 3:
print(a)
a += 1
a = 1
while a < 10:
print(f'2 x {a} = {a * 2}')
a += 1
b = 1
while b < 10:
a = 2
while a < 10:
print(f'{a} x {b} = {a * b}', end='\t')
a += 1
print()
b += 1
```
## 2024-06-13
#### 聖誕樹
```python=
user = int(input('請輸入數字: '))
for j in range(user):
for i in range(j+1):
print('*', end='')
print()
```
另一種寫法:
```python=
user = int(input('請輸入數字: '))
data = []
for i in range(user):
data += ['*']
print(''.join(data))
```
#### 完整九九乘法
```python=
a = ['aaron', 'andy', 'apple', 'alan']
for n in enumerate(a):
print(f'index: {n[0]}, data: {n[1]}')
for j in range(1, 10):
for i in range(2, 10):
print(f'{i} x {j} = {i * j:2d}', end='\t')
print()
```
#### 各種寫法
```python=
# 參與者名單
# 參與者名單
attendee = ['aaron', 'andy', 'apple', 'aaron', 'abner']
name = input('請輸入要查找的人名: ')
# 通用寫法
isAttend = False # 有沒有參加
for n in attendee:
if n == name:
isAttend = True
break
if isAttend:
print('有參加')
else:
print('無參加')
# 通用寫法二
new_list = []
for n in attendee:
if n == name:
new_list.append(n)
# if len(new_list) > 0:
if new_list:
print('有參加')
else:
print('無參加')
# 張大哥寫法
if [n for n in attendee if n == name]:
print('有參加')
else:
print('無參加')
# for-else寫法
for n in attendee:
if n == name:
print('有參加')
break
else:
print('無參加')
# in寫法
if name in attendee:
print('有參加')
else:
print('無參加')
if name in 'My name is aaron':
print('有出現')
else:
print('無出現')
```
#### 部分加分/篩選資料(for comprehension + 單行if)
```python=
# user_input = []
# for e in range(10000):
# score = input('請輸入成績(quit=離開): ')
# if score == 'quit':
# break
# else:
# user_input.append(int(score))
# print(user_input)
# # 處理成績
# # new_list = []
# # for s in user_input:
# # if s < 60:
# # new_list.append(s + 10)
# # else:
# # new_list.append(s)
# # 使用單行if
# # new_list = []
# # for s in user_input:
# # new_list.append(s + 10 if s < 60 else s)
# # 將小於60的數字加上10
# new_list = [s + 10 if s < 60 else s for s in user_input]
# print(f'不及格加分: {new_list}')
# 只列出及格的分數
a = [9, 58, 63, 100]
new_list = []
for b in a:
if b >= 60:
new_list.append(b)
new_list = [b for b in a if b >= 60]
print(new_list)
```
#### 加分
```python=
user_input = []
for e in range(10000):
score = input('請輸入成績(quit=離開): ')
if score == 'quit':
break
else:
user_input.append(int(score))
print(user_input)
# 處理成績
# new_list = []
# for s in user_input:
# if s < 60:
# new_list.append(s + 10)
# else:
# new_list.append(s)
# 使用單行if
# new_list = []
# for s in user_input:
# new_list.append(s + 10 if s < 60 else s)
new_list = [s + 10 if s < 60 else s for s in user_input]
print(new_list)
```
#### for comprehension
```python=
a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
# 一般寫法
new_list = []
for b in a:
new_list.append(b + 10)
print(new_list)
# for comprehension寫法
new_list = [b + 10 for b in a]
print(new_list)
a = [32, 54, 67, 88]
new_list = []
for b in a:
new_list += [b // 10]
print(new_list)
print([b // 10 for b in a])
```
#### range
```python=
a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
for b in a:
print(f'2 x {b} = {2 * b:2d}')
for b in a[1::2]:
print(b)
total = 0
for b in a:
total += b
print(f'總合為: {total}')
a_v2 = list(range(1, 10))
print(a_v2)
a_v2 = list(range(20, 3, -3))
print(a_v2)
a_v2 = list(range(-1, -6, -2))
print(a_v2)
a_v2 = list(range(3, 10, -1))
print(a_v2)
```
#### for-in迴圈
```python=
a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
for b in a:
print(f'2 x {b} = {2 * b:2d}')
```
## 2024-06-12
#### 切片
```python=
a = [1, 2, 3, 4, 5, 6, 7]
print(a[1:4])
print(a[:3])
print(a[3:])
print(a[:])
print(a[:-1])
print(a[-3:-1])
print(a[1:4:2])
print(a[::2])
print(a[::-1])
print(a[-3:-1:-1])
print(a[-2::-2])
print(a[5::-2])
print(a[::len(a)-1])
print(a[:2] + a[len(a)-2::])
```
#### list
```python=
import copy
a = [1, 2, 3, 6, '嗨', True]
print(type(a), len(a))
# 新增資料
a.append('OK') # 從後面新增一筆資料
a.insert(0, 'KO')
a += ['99'] # a = a + ['99']
a.append([5, 6, 7]) # 在原本list內新增一筆list資料
a.extend([5, 6, 7]) # 將新的list資料打散接在原本list後面
print(a)
# 讀取
print(a[5])
print(a.pop())
# print(a[6])
print(a)
# 修改資料
a[0] = 'HH'
# 刪除
a.remove(6) # 用資料本身來刪除
del a[0] # 用位置刪除資料
# 複製list
b = a.copy() # 複製內容
c = a # 複製參考
d = copy.deepcopy(a)
a[0] = 999
b[1] = 888
c[2] = 777
a[7][1] = 111
print(a)
print(b)
print(c)
print(d)
print(id(a), id(b), id(c), id(d))
print(a is b)
print(a is c)
```
#### 海象運算子
```python=
# user = int(input('請輸入數字: '))
if (user := int(input('請輸入數字: '))) % 2 == 0:
print(f'{user}為偶數')
else:
print(f'{user}為奇數')
```
#### match-case
```python=
year = int(input('請輸入民國年: '))
print(f'民國{year}年 = 西元{year+1911}年')
smile = year % 12
if smile == 1:
print(f'{year}為鼠年')
elif smile == 2:
print(f'{year}為牛年')
elif smile == 3:
print(f'{year}為虎年')
elif smile == 4:
print(f'{year}為兔年')
elif smile == 5:
print(f'{year}為龍年')
elif smile == 6:
print(f'{year}為蛇年')
elif smile == 7:
print(f'{year}為馬年')
elif smile == 8:
print(f'{year}為羊年')
elif smile == 9:
print(f'{year}為猴年')
elif smile == 10:
print(f'{year}為雞年')
elif smile == 11:
print(f'{year}為狗年')
else:
print(f'{year}為豬年')
match smile:
case 1:
print(f'{year}為鼠年')
case 2:
print(f'{year}為牛年')
case 3:
print(f'{year}為虎年')
case 4:
print(f'{year}為兔年')
case 5:
print(f'{year}為龍年')
case 6:
print(f'{year}為蛇年')
case 7:
print(f'{year}為馬年')
case 8:
print(f'{year}為羊年')
case 9:
print(f'{year}為猴年')
case 10:
print(f'{year}為雞年')
case 11:
print(f'{year}為狗年')
case 0:
print(f'{year}為豬年')
case _:
print('發生錯誤')
```
#### 計算潤年
```python=
year = int(input('請輸入年份: '))
# 寫法一
if year % 400 == 0:
print('潤年')
elif year % 4 == 0 and year % 100 != 0:
print('潤年')
else:
print('平年')
# 寫法二
if (year % 400 == 0) or (year % 4 == 0 and year % 100 != 0):
print('潤年')
else:
print('平年')
# 寫法三
print(f'{(year := int(input('請輸入年份: ')))}: {'潤年' if (year % 400 == 0) or (year % 4 == 0 and year % 100 != 0) else '平年'}')
```
#### `eval()`
##### code.txt
```python=
print('%d-%d-%d' % ($data))
```
##### data.txt
```python=
99, 88, 77
```
##### hello.py
```python=
with open('code.txt', 'r', encoding='utf-8') as file_code, open('data.txt', 'r', encoding='utf-8') as file_data:
code = file_code.readline()
data = file_data.readline()
print(code.replace('$data', data))
eval(code.replace('$data', data))
```
#### 格式化字串
```python=
name = 'aaron'
age = 99
money = 9999
score = 88.88
print(f'姓名: {name}, 年齡: {age}, 財產: {money}元, 平均分數: {str(score).rjust(10, '0')}') # f-string
print('姓名: %s, 年齡: %d, 財產: %010d, 平均分數: [%010.2f], %x, %X' % (name, age, money, score, 9999, 9999))
print('姓名: {}, 年齡: {}, 財產: {}元, 平均分數: {:010.2f}'.format(name, age, money, score))
```
#### print()寫入檔案
```python=
file = open('hello.txt', 'w') # with開啟的資源會自動做關閉
print('Hello Python', 'test', 'test', file=file)
file.close()
```
## 2024-06-11
#### 大小印度
```python=
a = 0x0011
print(a)
data_big = a.to_bytes(2, 'big')
data_little = a.to_bytes(2, 'little')
print(f'big: {data_big}')
print(f'little: {data_little}')
# ----------------------------
result = int.from_bytes(data_little, 'big')
print(result)
```
記憶體排列順序
參考: https://blog.gtwang.org/programming/difference-between-big-endian-and-little-endian-implementation-in-c/
#### 文字編碼
```python=
# 用utf-8編碼打開檔案
with open('test.txt', encoding='utf-8') as file:
data = file.readline()
print(data)
# 用cp950編碼寫入檔案
with open('test.txt', 'w') as file:
file.write('你好')
```
#### 浮點運算
```python=
print(0.6 / 2)
print(0.1 * 3) # IEEE-754
from decimal import Decimal
a = Decimal('0.1')
print(a * 3)
import random
a = random.randint(1, 5)
from random import randint
a = randint(1, 5)
```
> **參考:**
> https://medium.com/pyladies-taiwan/%E7%B2%BE%E7%A2%BA%E7%9A%84%E6%B5%AE%E9%BB%9E%E6%95%B8%E9%81%8B%E7%AE%97-28d34e652e51
#### 資料型態
```
print(r'abc\ndef\tght\ahi\x30\x31\'\"\\')
```
```python=
a = 5 # 整數 int
print(type(a))
a = 0b101110011 # 二進位整數
a = 0o7654 # 八進位整數
a = 0xFF # 16進位整數
print(bin(a)) # 將整數以2進位顯示
print(oct(a)) # 將整數以8進位顯示
print(hex(a)) # 將整數以16進位顯示
a = 1.1
print(type(a))
a = True
print(type(a))
a = 's'
print(type(a))
a = b's'
print(a, type(a))
a = '你好'.encode('utf-8')
print(a, type(a))
a = '\x30\x31\x32'
print(a)
a = float(3)
print(type(a))
```
#### 猜數字遊戲
```python=
# 引用隨機數模組
import random
# 產生1~5之間的隨機整數
answer = random.randint(1, 5)
print(f'答案: {answer}')
# 讓使用者輸入數字(資料必須轉型成int)
user = int(input('請猜一個1~5之間的數字: '))
if answer == user:
print('猜對了')
else:
print('猜錯了')
```
#### 成績判斷
```python=
score = int(input('請輸入你的分數: '))
# 基本
if score >= 60:
print('及格')
else:
print('不及格')
# 進階
score = int(input('請輸入你的分數: '))
print('及格') if score >=60 else print('不及格')
# 專業
print('及格' if int(input('請輸入你的分數: ')) >=60 else '不及格')
```
#### 判斷式
```python=
score = int(input('請輸入你的分數: '))
if score >= 60:
print('及格')
else:
print('不及格')
```
#### 常數
```python=
user = int(input('請輸入半徑(公分): '))
# 減少程式的魔術數字
PI = 3.1415926 # 常數
print(f'圓面積為: {user * user * PI} 平方公分')
```
Python並沒有不可修改的變數,也就是常數,但大家都會習慣用全大寫來命名變數,代表他是不可修改的常數
(但其實他還是能被修改,只是別去修改他)
#### 主動print
```python=
a = dir(__builtins__)
print(a)
```
#### 多行程式碼與三單/雙引號字串
```python=
a = 3
b = 4
c = 5
y = a + \
b + \
c
'''
這是多行註解
adsfjladjkflkasjdflakjdf
sdlkfjslkdjf
sdfjadjsaflkd
asdfjaslkdfjlassf
sadfjasdlfkjadf
lajdflkasjflkdsaflkasjdflkasjdfl
'''
print(y)
a = """adsfjladjkflkasjdflakjdf
sdlkfjslkdjf
sdfjadjsaflkd
asdfjaslkdfjlassf
sadfjasdlfkjadf
lajdflkasjflkdsaflkasjdflkasjdfl"""
print(a)
```
#### 連續指派
```python=
a = b = c = 3
a = 3
b = 3
c = 3
```
#### 算術運算子
```python=
# help('keywords')
# help('for')
# 數學運算(數字)
# +, -, *, /, %, //, **
print(5 + 3)
print(5 - 3)
print(5 * 3)
print(5 / 3)
print(5 % 3)
print(5 // 3)
print(5 ** 3)
# 數學運算(數字)
# +, *
print('abc' + 'def')
print('abc' * 3)
```
#### Python命名規則
1. 只能使用英文大小寫、數字、底線、中文
2. 名稱第一個字不能是數字
3. 英文字大小寫有別
4. 不可使用關鍵字
> 查Python全部關鍵字: `help('keywords')`
5. (不建議)用底線開頭或是使用內建涵式
## 2024-06-07
#### 目前程式碼
```
name = input('請輸入姓名: ')
birthday = input('請輸入生日: ')
phone = input('請輸入電話: ')
address = input('請輸入地址: ')
print('姓名:', name, '(生日:', birthday, '), 電話:', phone, ', 地址:', address)
print(f'姓名: {name}(生日: {birthday}), 電話: {phone}, 地址: {address}')
```
```
# user = input('請輸入一個數字: ') # input()收到的資料定是str型態
# 將user轉型成int
user = int(input('請輸入一個數字: '))
print(user, '的平方為:', user * user)
```
```python=
user = input('請輸入一個數字: ') # input()收到的資料定是str型態
# 將user轉型成int
user = int(user)
print(user, '的平方為:', user * user)
```
```python=
print('Hello Python.')
a = 2
print(a + 2)
a = '2'
print(a + '2')
# print(a + 2) # Ctrl - / 註解程式碼
sum = 4
print( type(a) )
print(True)
print('sjdlakjflkajdflkadjfldkjf')
print('Hello', a, 'ok', a, end='哈')
print('Hello' + a + 'ok' + a, end='哈')
print('Hello', a, 'ok', a, sep='-', end='哈')
print('Hello', a, 'ok', a, sep='-')
b = input('請隨意輸入: ')
print('你剛剛輸入的是:', b)
```
#### 程式語言排行榜
https://www.tiobe.com/tiobe-index/
#### Python安裝
- Visual Studio Code
- Python SDK
- Python Extension
> **注意:**
> 安裝Python SDK時,請在第一個安裝畫面下面的`Add python.exe to PATH`打勾,這樣未來在電腦的任何位置都可以執行Python相關指令。
#### 第一個程式
建立一個新的`.py`檔案
```python=
print('Hello Python.')
```
按下Ctrl-F5執行程式,VSCode會打開終端機畫面並執行:
```
Hello Python.
```
#### Python基礎
1. 單字後面有小括號的叫涵式,沒小括號是變數
2. Python的資料有形之分:
- `str`: 字串
- `int`: 整數
- `float`: 浮點數
- `bool`: 布林型態(True or False)
透過涵式`type()`可以偵測資料的型態。
3. 任何資料都需要透過`print()`才能在終端機上看到
## BASH練習
#### 題目一
請將`apt-cache search python`的結果僅顯示以`python3`為開頭套件名稱,例如:
```
...
python3-doris - Delft object-oriented radar interferometric software -- Python Tools
python3-drf-spectacular-sidecar-nonfree - Serve builds of Swagger UI and Redoc for Django REST framework (Python3)
python3-drf-yasg-nonfree - Yet another Swagger generator (Python3)
python3-hijra - Hijri Islamic Calendar converting functions for Python
python3-libzfs - Python libzfs bindings
python3-okasha - trivial WSGI web framework for Python
python3-okasha-examples - trivial WSGI web framework for Python (examples)
python3-othman - library providing access to Quranic text with a fast search index
python3-pycsw - OGC compliant metadata (Catalogue Service for the Web) server - Python 3
python3-pycuda - Python 3 module to access Nvidia‘s CUDA parallel computation API
python3-pynliner - CSS-to-inline-styles conversion tool for HTML - Python 3.x
python3-pynvml - Python3 bindings to the NVIDIA Management Library
python3-pyvkfft - Binding to the OpenCL backends of VkFFT - Python3
python3-pyvkfft-doc - Binding to the OpenCL backends of VkFFT - Documentation
python3-rna - ViennaRNA Python wrappers
python3-seqcluster - analysis of small RNA in NGS data
python3-sparkpost - SparkPost Python API client (Python 3)
python3-stravalib - tool for accessing and downloading Strava data from the Strava
python3-unrardll - Python wrapper for the unrar shared library
python3-vertica - native Python client for the Vertica database (Python 3)
```
#### 題目二
請前往`http://worldtimeapi.org/api/timezone/Asia/Taipei.txt`網址,將資料爬下來後,只顯示時間,例如:
```
abbreviation: CST
client_ip: 60.250.246.100
datetime: 2024-05-30T15:11:00.285739+08:00
day_of_week: 4
day_of_year: 151
dst: false
dst_from:
dst_offset: 0
dst_until:
raw_offset: 28800
timezone: Asia/Taipei
unixtime: 1717053060
utc_datetime: 2024-05-30T07:11:00.285739+00:00
utc_offset: +08:00
week_number: 22
```
只需顯示:
```
15:06:01
```
#### 題目三
將台積電股票資訊爬下來
網址: https://mis.twse.com.tw/stock/api/getStockInfo.jsp?ex_ch=tse_2330.tw&json=1&delay=0&_=1635167108897
回傳的JSON欄位說明:
| 欄位名稱 | 描述 |
| -------- | ------------------------------- |
| z | 當前盤中成交價 |
| tv | 當前盤中盤成交量 |
| v | 累積成交量 |
| b | 揭示買價(從高到低,以_分隔資料) |
| g | 揭示買量(配合b,以_分隔資料) |
| a | 揭示賣價(從低到高,以_分隔資料) |
| f | 揭示賣量(配合a,以_分隔資料) |
| o | 開盤價格 |
| h | 最高價格 |
| l | 最低價格 |
| y | 昨日收盤價格 |
| u | 漲停價 |
| w | 跌停價 |
| tlong | 資料更新時間(單位:毫秒) |
| d | 最近交易日期(YYYYMMDD) |
| t | 最近成交時刻(HH:MI:SS) |
| c | 股票代號 |
| n | 公司簡稱 |
| nf | 公司全名 |
#### 注意
爬下來的資料請透過管線給`jq`指令做格式化,比較容易拆解資料。
請抓取`nf`欄位和`z`欄位資訊,然後組成結果如下:
```
台灣積體電路製造股份有限公司 今日價格: 838
```
#### 題目四
取得目前目錄下全部的子目錄和檔案佔據的硬碟空間,並以下面的格式顯示
```
此目錄檔案總大小為: 185M
```
> **提示:**
> 可以使用`du`指令計算
##### 題目五
從google trends抓取熱門搜尋排行榜資料,並以下面格式輸出到畫面上:
```
林雅各:1000+
趙天麟:1000+
魔獸:1000+
黃仁勳:5萬+
MBTI:5萬+
內田有紀:1萬+
Popeyes:1萬+
台灣野馬隊:5000+
李西河:5000+
李海魯肉飯:5000+
炎亞綸:2000+
廣達:2000+
長庚大學:2000+
張學友:2000+
東海大學:2000+
中興大學:2000+
雷驤:2000+
T1:2000+
東吳大學:2000+
TAT:2000+
噩盡島:2000+
MSCI 調整:1000+
今永昇太:1000+
```
##### Google Trends資料抓取curl指令
```bash=
curl -s 'https://trends.google.com/trends/api/dailytrends?hl=zh-TW&tz=-480&geo=TW&hl=zh-TW&ns=15' -H 'accept: application/json, text/plain, */*' -H 'accept-language: zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7' -H 'cookie: __utmc=10102256; __utma=10102256.1988690101.1717122572.1717122582.1717124682.2; __utmz=10102256.1717124682.2.2.utmcsr=trends.google.com|utmccn=(referral)|utmcmd=referral|utmcct=/; __utmt=1; __utmb=10102256.2.9.1717124699155; SEARCH_SAMESITE=CgQIm5sB; AEC=AQTF6HxX-R9ngeztx-zrIwJTfvmFSLN9rTvkfN4O25Q1PskDRAc6PYsKfSk; NID=514=i4H9axvH-OMMwM0VPNqAgrbQxLw9PtToEHwpe9CaoQ_cgNip9k7bhLdpcu1r9SH4xvndMse2zw8OQT63tTwF-CfJLzYUT559XM5FUoTKHbZ8H0VCaudYzYO6ywwUkmUcvvmAGZXKQFV3dWgjGT3Ns8TWjT7OnGIWOsWnyKUFhnzLbWY4e9Ixb4pG2ZvPV8Kq_IjWQAHc1Qro_u6SETkX6hNfUNd8EqBQG47voaopVYFgRc8jlWqPVyVEbpaFEeRXCwgJtisy5ok8-gdUs7sX4sOaFE9sfsr7sSZUMU2Lw3-7pvA1VFA8ZvOuXpge; _gid=GA1.3.377492726.1717122573; 1P_JAR=2024-05-31-03; OTZ=7580345_24_24__24_; _ga=GA1.3.1988690101.1717122572; _ga_VWZPXDNJJB=GS1.1.1717122571.1.1.1717124894.0.0.0' -H 'priority: u=1, i' -H 'referer: https://trends.google.com/trends/trendingsearches/daily?geo=TW&hl=zh-TW' -H 'sec-ch-ua: "Google Chrome";v="125", "Chromium";v="125", "Not.A/Brand";v="24"' -H 'sec-ch-ua-arch: "x86"' -H 'sec-ch-ua-bitness: "64"' -H 'sec-ch-ua-full-version: "125.0.6422.113"' -H 'sec-ch-ua-full-version-list: "Google Chrome";v="125.0.6422.113", "Chromium";v="125.0.6422.113", "Not.A/Brand";v="24.0.0.0"' -H 'sec-ch-ua-mobile: ?0' -H 'sec-ch-ua-model: ""' -H 'sec-ch-ua-platform: "Windows"' -H 'sec-ch-ua-platform-version: "10.0.0"' -H 'sec-ch-ua-wow64: ?0' -H 'sec-fetch-dest: empty' -H 'sec-fetch-mode: cors' -H 'sec-fetch-site: same-origin' -H 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36' -H 'x-client-data: CIS2yQEIorbJAQipncoBCPbuygEIlqHLAQiFoM0BCN3uzQEIpYrOAQjik84BCOiTzgEI4pfOAQjUmM4BGPXJzQE=' > googletrends.txt
```
#### 題目六
###### 取得中壢區的今天天氣
需要取得的資訊有:
- 現在氣溫
- 天氣狀況
- 目前降雨率
> **備註:**
> 金鑰是很敏感的資料,貼上答案時,請記得把金鑰刪除再貼上
#### 題目七
##### 讓使用者從鍵盤輸入資料,並存到temp檔案中,最後將temp檔案的內容顯示到畫面上:
```
您輸入的資料是: xxxxxxxxx
```
#### 題目八
猜數字遊戲,請產生1~10之間的隨機數,讓使用者輸入一個數字,如果猜對了,則回應:
```
恭喜,猜對了。
```
如果數字不一樣,則:
```
可惜,猜錯了
```
> 提示:
> 產生1~10之間隨機數的指令: `$ shuf -i 1-10 -n 1`
#### 題目九
寫一程式,抓取桃園ubike資訊,使用者可以輸入站名,然後回應剩餘的車輛數量:
- 輸入的站名必須全部吻合
- 如果少於10輛(包含), 請顯示: 剩n輛囉,請加快腳步,以免遺憾
- 如果超過10量可以借, 請顯示: 還超過10量可以借,不急
- 如果找不到站名則顯示: 無此站台
#### 題目十
寫一程式,帶入帳號參數後,可以告知該帳號是否正在線上
> **提示:**
> `who`或`w`只領可以查詢目前有哪些帳號登入中
> `exit`指令用來離開shell
#### 題目11
寫一程式,讓使用者輸入任意個數字,輸入quit可以結束輸入,當結束的時候,把使用者輸入的數字全部顯示出來,如:
```
22 33 44 55
```
#### 題目12
寫一程式,可以讀取目前目錄下的所有執行檔
#### 題目13
寫一程式,可以在畫面上輸出指定層數的聖誕樹
例如:
```
$ tree.sh 5
```
會顯示
```
*
**
***
****
*****
```
#### 題目14
寫一程式,可以顯示九九乘法表如下:
```
2 x 1 = 2 3 x 1 = 3 4 x 1 = 4 5 x 1 = 5
2 x 2 = 4 3 x 2 = 6 4 x 2 = 8 5 x 2 = 10
2 x 3 = 6 3 x 3 = 9 4 x 3 = 12 5 x 3 = 15
2 x 4 = 8 3 x 4 = 12 4 x 4 = 16 5 x 4 = 20
2 x 5 = 10 3 x 5 = 15 4 x 5 = 20 5 x 5 = 25
2 x 6 = 12 3 x 6 = 18 4 x 6 = 24 5 x 6 = 30
2 x 7 = 14 3 x 7 = 21 4 x 7 = 28 5 x 7 = 35
2 x 8 = 16 3 x 8 = 24 4 x 8 = 32 5 x 8 = 40
2 x 9 = 18 3 x 9 = 27 4 x 9 = 36 5 x 9 = 45
6 x 1 = 6 7 x 1 = 7 8 x 1 = 8 9 x 1 = 9
6 x 2 = 12 7 x 2 = 14 8 x 2 = 16 9 x 2 = 18
6 x 3 = 18 7 x 3 = 21 8 x 3 = 24 9 x 3 = 27
6 x 4 = 24 7 x 4 = 28 8 x 4 = 32 9 x 4 = 36
6 x 5 = 30 7 x 5 = 35 8 x 5 = 40 9 x 5 = 45
6 x 6 = 36 7 x 6 = 42 8 x 6 = 48 9 x 6 = 54
6 x 7 = 42 7 x 7 = 49 8 x 7 = 56 9 x 7 = 63
6 x 8 = 48 7 x 8 = 56 8 x 8 = 64 9 x 8 = 72
6 x 9 = 54 7 x 9 = 63 8 x 9 = 72 9 x 9 = 81
```
## 2024-06-06
##### 取得今天日期的shell script
```
#!/bin/bash
while :
do
date +"%Y/%m/%d %H:%M:%S" >> /home/happy/m_service2.log
sleep 1
done
```
##### 掛載成service
1. 且換成root權限
```
$ sudo su
```
2. 切換到service目錄下
```
$ cd /etc/systemd/system
```
3. 建立我們的service
```
$ vim my-service.service
```
4. 編輯設定
```
[Unit]
Description=My Service
[Service]
Type=simple
Restart=always
ExecStart=/home/happy/my_service.sh >> /home/happy/m_service.log
User=happy
[Install]
WantedBy=multi-user.target
```
5. 建立service
```
$ systemctl enable my-service
```
6. 啟動service
```
$ systemctl start my-service
```
7. 完成。
> **注意:**
> 1. 如果使用的帳號不是happy,必須改成你自己的帳號名稱和自己的home目錄路徑
> 2. 完成後可以到自己的home目錄下確認有沒有my_service.log檔案
8. 如果你後來有修改過my-service.service,你會需要執行:
```
$ systemctl daemon-relad
```
9. 如果你有改過shell script,你需要執行:
```
$ systemctl restart my-service
```
#### scp
格式:
```
$ scp {來源檔案位置} {目的檔案位置}
```
> **備註:**
> 來源和目的可以都是遠端主機或是本地端檔案
```
$ scp happy@172.19.106.33:test.json happy2@172.19.106.33:test.json
```
> **備註:**
> Windows 10命令提示字元或PowerShell開始支援`scp`指令
#### WinSCP
Windows下可以下載WinSCP工具: https://winscp.net/eng/download.php
#### nc
server
```
$ nc -l 9999
```
client
```
$ nc 172.19.106.33 9999
```
> **注意:**
> 對方要先啟動server端,client才能成功執行
#### MQTT
安裝
```
$ sudo apt-get install mosquitto mosquitto-clients -y
```
修改設定,將mqtt server公開到網路上
/etc/mosquitto/conf.d/default.conf
```
allow_anonymous true
listener 1883
```
> **備註:**
> 1. 預設MQTT剛裝好的時候沒有default這個設定檔,必須自己建立才能透過網路連線
> 2. 副檔名一定要有`.conf`
重新啟動服務
```
$ systemctl restart mosquitto
```
訂閱主題chat
```
$ mosquitto_sub -h 172.19.106.33 -p 1883 -t chat
```
發布訊息
```
$ mosquitto_pub -h 172.19.106.33 -p 1883 -t chat -m "Hello"
```
## 2024-06-05
#### while迴圈
##### 第一種用法: 計數式迴圈
```bash=
#!/bin/bash
# 用計數的方式來執行迴圈
#i=0
#while [ $i -lt 10 ]
#do
# echo "i = $i"
#
# let "i++"
#done
#
#echo 'End of while'
#
## 透過標記來結束迴圈
#read -p "請輸入資料(quit=離開): " user
#
#while [ "$user" != 'quit' ]
#do
# echo "=> $user"
#
# read -p "請輸入資料(quit=離開): " user
#done
#
#echo "End of while"
#
#while :
#do
#
# read -p "請輸入資料(quit=離開): " user
#
# if [ "$user" = 'quit' ]
# then
# break
# fi
#
#done
#
#echo "End of while"
#pc=`shuf -i 1-10 -n 1`
#echo "answer=$pc"
#
#count=0
#
#while :
#do
# read -p '請猜一個數字: ' user
# let "count++"
#
# if [ $pc -eq $user ]
# then
# echo "猜對了,總共猜了$count次"
# break
# else
# echo '猜錯了'
# fi
#
#done
#
#echo '遊戲結束.'
#arr=(22 33 44 55 66)
#echo ${arr[1]}
#arr[1]=99
#arr+=(8)
#echo ${arr[@]}
#echo ${#arr[@]}
#
arr=(1 2 3 4 5 6 7 8 9 10)
index=0
while [ $index -lt ${#arr[@]} ]
do
if [ $((arr[index] % 2)) -eq 1 ]
then
let "index++"
continue
fi
echo ${arr[index]}
let "index++"
done
```
#### for-in迴圈
```bash=
arr=(1 2 3)
for var in ${arr[@]}
do
echo $var
done
total=0
for var in {1..10..1}
do
let "total+=var"
done
echo "總和: $total"
```
```bash=
total=0
for var in `seq $1 1 $2`
do
let "total+=var"
done
echo "總和: $total"
```
#### 陣列
建立陣列有三筆資料的
```
a=(1 2 3)
```
取得陣列第二筆資料
```
echo ${a[1]}
```
> 會得到2
取得陣列全部資料
```
$ ehco ${a[@]}
```
修改第三筆資料為99
```
$ a[2]=99
```
新增一筆資料
```
$ a+=(8)
```
刪除1這筆資料
```
a=(${arr[@]/1})
```
## 2024-06-04
#### 文字版天氣資訊
$ https://github.com/chubin/wttr.in
```
Weather report: 中壢
\ / Partly cloudy
_ /"".-. +26(28) °C
\_( ). ↙ 20 km/h
/(___(__) 10 km
0.0 mm
┌─────────────┐
┌──────────────────────────────┬───────────────────────┤ Tue 04 Jun ├───────────────────────┬──────────────────────────────┐
│ Morning │ Noon └──────┬──────┘ Evening │ Night │
├──────────────────────────────┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────┤
│ Cloudy │ Overcast │ Cloudy │ \ / Partly Cloudy │
│ .--. +22(25) °C │ .--. +24(25) °C │ .--. +23(25) °C │ _ /"".-. +23(25) °C │
│ .-( ). ↙ 19-30 km/h │ .-( ). ↙ 18-26 km/h │ .-( ). ← 16-27 km/h │ \_( ). ← 16-27 km/h │
│ (___.__)__) 10 km │ (___.__)__) 10 km │ (___.__)__) 10 km │ /(___(__) 10 km │
│ 0.0 mm | 0% │ 0.0 mm | 0% │ 0.0 mm | 0% │ 0.0 mm | 0% │
└──────────────────────────────┴──────────────────────────────┴──────────────────────────────┴──────────────────────────────┘
Location: 中壢區, 桃園市, 臺灣 [24.9653531,121.224926]
```
#### 執行運算的幾種的幾種方式
- 雙小括號: `$((運算式))`
- 中括號: `$[運算式]`
- let: `let "運算式"`
#### 算數運算子
|||
|-|-|
|+|加法運算|
|-|減法運算|
|*|乘法運算|
|/|除法運算|
|%|餘數運算|
|`**`|指數運算(次方)|
|++|將變數加1(須注意放變數前面跟後面的差別)|
|--|將變數減1(須注意放變數前面跟後面的差別)|
> **注意:**
> `++`或`--`當放在變數後面時,會先執行完當前該行運算式後才會將變數內容加1,如果`++`放在變數前面,則是會將變數先1,然後才開始執行當前的運算式
#### alias 幫指令取綽號
```
$ alias mu='./my_ubike.sh'
$ alias lsl='ls -l'
```
#### 取消化名
```
$ unalias mu
$ unalias lsl
```
#### 看所有的化名
```
$ alias
```
#### csvtool
1. 安裝
```
$ sudo apt-get install csvtool
```
2. 下載ubike資料並存到ubike.csv
```
$ wget https://data.tycg.gov.tw/api/v1/rest/datastore/a1b4714b-3b75-4ff8-a8f2-cc377e4eaa0f?format=csv -O ubike.csv
```
3. 擷取ubike.csv的第4(站名)和第13(剩餘量)欄位
```
$ csvtool col 4,13 ubike.csv
```
4. 過濾出健行科技大學的資料
```
$ csvtool col 4,13 ubike.csv | grep 健行科技大學
```
5. 取得健行科技大學的ubike剩餘量
```
$ csvtool col 4,13 ubike.csv | grep 健行科技大學 | cut -d, -f2
```
#### 如果出現安裝錯誤
錯誤訊息:
```
E: Could not get lock /var/lib/dpkg/lock-frontend. It is held by process 2912043 (apt-get)
N: Be aware that removing the lock file is not a solution and may break your system.
E: Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend), is another process using it?
```
先檢查是哪一個程序正在把套件庫鎖死了:
```
$ sudo lsof /var/lib/dpkg/lock-frontend
```
輸出:
```
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
apt-get 2912043 root 4uW REG 252,0 0 131956 /var/lib/dpkg/lock-frontend
```
透過PID把該程序停掉
```
$ sudo kill -9 2912043
```
> **備註:**
> 2912043只是這裡的範例PID, 你自己的系統PID應該會不一樣
#### 多重if判斷式
```bash=
#!/bin/bash
echo '---------------------------------------'
echo ' 算命 '
echo ' 版本: v1.00 '
echo '---------------------------------------'
# 抽籤
pc=`shuf -i 1-10 -n 1`
printf 抽籤中.;sleep 1;printf .;sleep 1;printf .;sleep 1;printf .;sleep 1;printf .;sleep 1
echo
echo
printf '抽籤結果: '
if [ $pc -eq 1 ]
then
echo '今天會撿到錢.'
elif [ $pc -eq 2 ]
then
echo '今天發獎金.'
elif [ $pc -eq 3 ]
then
echo '今天中彩卷.'
elif [ $pc -eq 4 ]
then
echo '今天加薪.'
else
echo '沒事.'
fi
printf '抽籤結果: '
# case的寫法
case "$pc" in
1)
echo '今天會撿到錢.'
;;
2)
echo '今天發獎金.'
;;
3)
echo '今天中彩卷.'
;;
4)
echo '今天加薪.'
;;
*)
echo '沒事.'
esac
echo '掰~'
```
#### 邏輯運算
- `-a`: 代表 而且(and),兩邊的條件事都要成立,結果才會成立。
- `-o`: 代表 或(or),兩邊的條件只要有一邊成立,其結果即為成立。
- `!`: 反向,將成立變成不成立,不成立變成成立。
```bash=
#!/bin/bash
echo '============================================='
echo ' 和電腦猜拳'
echo ' 版本: v1.00'
echo '============================================='
pc=`shuf -i 0-2 -n 1`
echo "電腦出了: $pc"
read -p "請出拳(0=剪刀, 1=石頭, 2=布): " user
if [ $pc -eq 0 -a $user -eq 1 ]
then
echo '你贏了!'
elif [ $pc -eq 0 -a $user -eq 2 ]
then
echo '你輸了.'
elif [ $pc -eq 1 -a $user -eq 0 ]
then
echo '你輸了.'
elif [ $pc -eq 1 -a $user -eq 2 ]
then
echo '你贏了.'
elif [ $pc -eq 2 -a $user -eq 0 ]
then
echo '你贏了.'
elif [ $pc -eq 2 -a $user -eq 1 ]
then
echo '你輸了.'
else
echo '平手'
fi
```
#### 檔案判斷
判斷檔案a.txt是否存在
```
[ -f 'a.txt']
```
判斷test是否為目錄
```
[ -d 'test']
```
判斷檔案室否有x權限
```
[ -x 'test.log']
```
## 2024-06-03
#### Shell Script
四則運算
```
$ a=3
$ let a+=3
$ echo $a
```
> 6
```
$ a = abcdef
$ let b=${a/cde/9}
$ echo $a
```
> ab9f
全部取代:
```
$ a = 123123
$ let b=${a//1/9}
$ echo $a
```
> 923923
#### 判斷式
```
#!/bin/bash
if [ "$1" -gt 10 ]
then
echo "你的輸入大於10"
else
echo "你的輸入小於等於10"
fi
```
#### 字串判斷
判斷字串是否為空
```bash=
$ [ "999" ]
$ echo $?
```
> 0(成立)
判斷字串是否相等
```
$ [ "333" = "555" ]
$ echo $?
```
> 1(不成立)
判斷字串是否不相等
```
$[ "333" != "555" ]
```
> 0(成立)
判斷字串是否不為空(空=不成立, 不為空=成立)
```
$ [ -n "999" ]
$ $?
```
> 0
判斷字串是否為空(空=成立, 不為空=不成立)
```
$ [ -z "999" ]
$ $?
```
> 1
```
$ [ 3 -eq 3 ];echo $?
```
> 0
```
$ [ 3 -ne 3 ];echo $?
```
> 1
```
$ [ 5 -gt 3 ];echo $?
```
> 0
```
$ [ 5 -lt 3 ];echo $?
```
> 1
```
$ [ 4 -ge 4 ];echo $?
```
> 0
```
$ [ 4 -le 4 ];echo $?
```
> 0
#### Linux發行版本佔有率
Ubuntu: 24.7%
Debian: 13.3%
CentOS: 5.5%
Red Hat
0.4%
AlmaLinux
0.3%
Gentoo
0.3%
Fedora
0.1%
SuSE
less than 0.1%
CloudLinux
less than 0.1%
Raspbian
less than 0.1%
Scientific Linux
less than 0.1%
Turbolinux
less than 0.1%
Mageia
less than 0.1%
Mandriva
less than 0.1%
Red Star OS
less than 0.1%
Trisquel
less than 0.1%
PCLinuxOS
less than 0.1%
Asianux
less than 0.1%
PLD Linux
less than 0.1%
Unknown
55.3%
> **備註:**
> 資料來源:https://w3techs.com/technologies/details/os-linux
#### Linux目錄架構
Linux 目錄結構
Comment
Suggest edit
在 Linux 中,將所有的硬體裝置都視為檔案
指令、硬體等等,每一個就是一個檔案
/ : 根目錄
/ 下的系統檔案只有 root 管理者有權限變更與更改
因此對檔案目錄的理解是相當重要的
一般來說,所在位置都會在使用者目錄下
透過 cd ../.. 可回到最上層根目錄
檔案操作相關指令
圖片來源
目錄
重要常見目錄
/bin
/dev
/etc
/home
/var
/tmp
其餘目錄
/boot
/lib
/lib32、/lib64
/media
/mnt
/opt
/run
/proc
/root
/srv
/usr
/sbin
/usr 底下目錄結構
/usr/bin
/usr/include
/usr/local
參考
重要常見目錄
/bin
binary file
存放了提供所有使用者經常使用的指令
/dev
device
存放系統所有的外部設備檔案
可以透過這些文件去存取外部的設備
記憶體
硬碟
虛擬終端
Console
/etc
etcetera
存放作業系統和應用程式與各項伺服器的設定檔
開機啟動設定檔 (init.d)
安全性設定檔 (security)
使用者資料 (passwd)
應用程式 (python)
破壞了可能會造成無法開機、資料損壞等後果
/etc/network/ : 存放網路配置檔案
/home
存放了使用者的個人檔案
每個使用者都會有一個以自己帳號命名的目錄在 home 下面
也就是每個使用者自己的主目錄,可以在自己的主目錄下存放個人的檔案
使用者登入之後就會直接進到自己的主目錄下
/var
variable
存放著常態性變動的檔案
cache (快取)
log
登入、系統、運行服務都會產生相應的 log 紀錄存放至此
系統有問題可以從這裡查看 log 訊息來除錯
mail (尚未寄出的郵件或是接收郵件的地方)
/tmp
temporary
存放一些暫時性的文件
系統運行過程中的暫存檔案
使用者的暫存檔案
其餘目錄
/boot
boot 目錄存放的是啟動 Linux 時所需要使用的一些核心文件
連接文件
.iso 檔案
檔案損壞會導致系統無法開機
/lib
存放了 Linux 在執行或編譯時會使用到的一些共用函庫
執行 /bin、/sbin 目錄中執行檔所需的函式庫
許多應用程式執行也幾乎都需要從這裡獲取所需的函式庫來執行
/lib32、/lib64
分別存放 32 位元、64 位元的函式庫
/media
Linux 會將外部的連結設備 (硬碟、光碟機) 掛載到 media 目錄下
/mnt
mount
檔案系統的臨時掛載點
透過手動將暫時性檔案掛載在此以進行存取
掛載一個 .iso 檔並將資料從這個 .iso 檔取出來,取得需要的資料之後就可以卸載這個檔案
在 /media 目錄還沒有出現之前,/mnt 目錄的功能就和 /media 一樣
現在多了 /media 目錄會自動掛載那 /mnt 就多用於暫時性的掛載
/opt
option
給第三方的軟體 (自行額外安裝的軟體) 放置的目錄
/run
暫時的文件系統
儲存系統啟動之後的訊息
/proc
process
存放目前系統核心和正在執行的程式資訊
系統核心 ( CPU )
記憶體
行程 (process) 資訊
網路狀態
這些資料都是存在記憶體中,並不佔硬碟空間,所以是虛擬的檔案系統
透過 sysctl 指令或修改 /proc/sys 目錄中的檔案,來調整系統的參數
/root
系統管理員的主目錄
/srv
service
存放了一些網路服務啟動後所需要用到的資料
WWW
FTP
/usr
unix software resource
存放 Unix 作業系統軟體資源
作業系統的資訊
應用程式的文件
類似於 Windows 的 ProgramFiles
/sbin
super binaries
存放了只有系統管理員可以使用的指令
fdisk (硬碟分割)
shutdown (關機)
ifconfig (查看網路狀態)
還原系統
/usr 底下目錄結構
/usr/bin
多數日常應用程式存放的位置
對系統至關重要的程式不應放在此文件夾中
/usr/include
存放 C/C++ 標頭檔
/usr/local
新裝的系統中這個文件夾是空的,可以用於存放個人安裝的軟體
參考
Linux 系统目录结构
Ubuntu根目錄下各資料夾的功能詳細介紹
#### 檔案與目錄管理指令
- ls: 列出檔案
> -a :全部的檔案,連同隱藏檔( 開頭為 . 的檔案) 一起列出來(常用)
> -A :全部的檔案,連同隱藏檔,但不包括 . 與 .. 這兩個目錄
> -d :僅列出目錄本身,而不是列出目錄內的檔案資料(常用)
> -f :直接列出結果,而不進行排序 (ls 預設會以檔名排序!)
> -F :根據檔案、目錄等資訊,給予附加資料結構,例如:
> *:代表可執行檔; /:代表目錄; =:代表 socket 檔案; |:代表 FIFO 檔案;
> -h :將檔案容量以人類較易讀的方式(例如 GB, KB 等等)列出來;
> -l :長資料串列出,包含檔案的屬性與權限等等資料;(常用)
>-r :將排序結果反向輸出,例如:原本檔名由小到大,反向則為由大到小;
> -R :連同子目錄內容一起列出來,等於該目錄下的所有檔案都會顯示出來;
> -S :以檔案容量大小排序,而不是用檔名排序;
> -t :依時間排序,而不是用檔名。
> --color=never:不要依據檔案特性給予顏色顯示;
> --color=always:顯示顏色
> --color=auto:讓系統自行依據設定來判斷是否給予顏色
> --full-time:以完整時間模式 (包含年、月、日、時、分) 輸出
> --time={atime,ctime} :輸出 access 時間或改變權限屬性時間 (ctime) 而非內容變更時間 (modification time)
- cd:變換目錄
- pwd:顯示目前的目錄
- mkdir:建立一個新的目錄
- rmdir:刪除一個空的目錄
- cp: 複製檔案或目錄
> -a :相當於 -dr --preserve=all 的意思,至於 dr 請參考下列說明;(常用)
> -d :若來源檔為連結檔的屬性(link file),則複製連結檔屬性而非檔案本身;
> -f :為強制(force)的意思,若目標檔案已經存在且無法開啟,則移除後再嘗試一次;
> -i :若目標檔(destination)已經存在時,在覆蓋時會先詢問動作的進行(常用)
> -l :進行硬式連結(hard link)的連結檔建立,而非複製檔案本身;
> -p :連同檔案的屬性(權限、用戶、時間)一起複製過去,而非使用預設屬性(備份常用);
> -r :遞迴持續複製,用於目錄的複製行為;(常用)
> -s :複製成為符號連結檔 (symbolic link),亦即『捷徑』檔案;
- rm: 移除檔案或目錄
> -f :就是 force 的意思,忽略不存在的檔案,不會出現警告訊息;
> -i :互動模式,在刪除前會詢問使用者是否動作
> -r :遞迴刪除啊!最常用在目錄的刪除了!這是非常危險的選項!!!
- mv: 移動檔案與目錄,或更名
- basename: 取得路徑的檔案名稱
- dirname: 取得路徑的目錄名稱
- cat: 由第一行開始顯示檔案內容
- tac: 從最後一行開始顯示,可以看出 tac 是 cat 的倒著寫!
- nl: 顯示的時候,順道輸出行號!
- more: 一頁一頁的顯示檔案內容
- less: 與 more 類似,但less可以往前翻頁!
- head: 只看頭幾行
- tail: 只看尾巴幾行
- od: 以二進位的方式讀取檔案內容!
> -t :後面可以接各種『類型 (TYPE)』的輸出,例如:
> a :利用預設的字元來輸出;
> c :使用 ASCII 字元來輸出
> d[size] :利用十進位(decimal)來輸出資料,每個整數佔用 size bytes ;
> f[size] :利用浮點數值(floating)來輸出資料,每個數佔用 size bytes ;
> o[size] :利用八進位(octal)來輸出資料,每個整數佔用 size bytes ;
> x[size] :利用十六進位(hexadecimal)來輸出資料,每個整數佔用 size bytes ;
- jq: 將JSON字串格式化後輸出
- touch: 建立新的檔案
- file: 觀察檔案類型
- which: 尋找『執行檔』的所在路徑
- mktemp: 建立暫存檔案
#### 執行檔路徑的變數: $PATH
用來執行不在目前目錄下的指令
```
$ echo $PATH
```
新增一個路徑
```
$ export $PATH:/home/aaron
```
> **備註:**
> 資料來源: https://linux.vbird.org/linux_basic/centos7/0220filemanager.php#ls
#### Shell程式設計
##### 四則運算
```
```
## 2024-05-31
#### du
顯示目前目錄下每個檔案大小和總大小(含隱藏檔)
```
$ du
```
顯示目前目錄下每個檔案大小和總大小(含隱藏檔),並以容易閱讀的大小單位顯示
```
$ du -h
```
計算目前目錄下非隱藏檔的檔案總大小
```
$ du -h --exclude "./.*"
```
#### paste
將1.txt和2.txt的每一行內容各自合併在一起
```bash=
$ paste 1.txt 2.txt
```
將1.txt和2.txt的每一行內容各自合併在一起,並以`:`作為分隔符號
```bash=
$ paste -d: 1.txt 2.txt
```
#### 安裝nginx
更新套件庫
```
sudo apt-get update
```
安裝nginx套件
```
sudo apt-get install nginx
```
檢查nginx的服務狀態(方式一)
```
service nginx status
```
檢查nginx的服務狀態(方式二)
```
systemctl status nginx
```
找出目前電腦的IP
```
ip a
```
#### 編輯網頁
預設網頁存放在`/var/www/html`目錄下:
```
$ sudo su
$ cd /var/www/html
$ vim index.nginx-debian.html
```
> **注意:**
> 此目錄需要喜統權限才能編輯
```
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>這是我的伺服器</h1>
...
</html>
```
下載樣板
```bash=
wget https://html5up.net/massively/download
```
安裝zip解壓縮套件
```
apt-get install unzip
```
解壓縮網站樣板
```
$ unzip download
```
編輯首頁
```
$ vim index.html
```
> **注意:**
> 上述網站相關操作相關指令都必須先`sudo su`切換到root帳號才能執行
## 2024-05-30
#### 環境變數
##### env
看目前所有環境變數
```
$ env
```
##### export
新增環境變數TEST
```
$ export TEST=Hello
```
##### 取得環境變數
```
$ echo $TEST
```
##### 刪除環境變數
```
$ unset TEST
```
#### 將環境變數永久設定
##### 區域型(只有自己看的到)
```
~/.bashrc
```
##### 全域型(全部帳號都看的到)
```
/etc/environment
```
或
```
/etc/profile
```
#### 新增一般變數
新增hello變數,值為ok
```
$ hello=ok
```
#### 從鍵盤讀取使用者輸入
從鍵盤讀取使用者輸入,並存入aaron變數中
```
$ read aaron
```
從鍵盤讀取使用者輸入,並且加上提示文字,並存入aaron變數中
```
$ read -p "請輸入數字: " aaron
```
從鍵盤讀取使用者輸入,並且加上提示文字,倒數10秒,並存入aaron變數中
```
$ read -t 10 -p "請輸入數字: " aaron
```
#### 文字處理
##### cat
```
$ cat > test.txt
```
> 輸入完畢後按下Ctrl-C結束,輸入的資料都會存到test.txt檔案中
##### uniq去除連續重複資料行
將a.txt連續重複的行去掉
```
$ uniq a.txtg
```
將a.txt連續重複的行去掉,並顯示重複次數
```
$ uniq -c a.txtg
```
|||
|-|-|
|-c|輸出重複的次數|
|-d|僅輸出重複的|
|-i|忽略大小寫|
|-u|僅輸出不重複的|
##### wc計算文字
計算行數
```
$ wc -l a.txt
```
計算單字數
```
$ wc -w a.txt
```
計算字元數
```
$ wc -c a.txt
```
> -l行數、-w字數、-c字元數
##### grep
將檔名包含txt的檔案資訊過濾出來
```
$ ls -l | grep txt
```
找出Manager程式是否執行中
```
$ ps aux | grep Manager
```
找出名稱是Manager開頭的程式是否執行中
```
$ ps aux | grep ^Manager
```
找出名稱是Manager結尾的程式是否執行中
```
$ ps aux | grep Manager$
```
排除名稱包含Manager的其它程式是否執行中
```
$ ps aux | grep -v Manager
```
> **補充:**
> `-w`: 整行文字都要完全符合
> `|`: 只要一個文字符合就會被篩選出來
##### head
##### tail
取得a.txt內容的最後一行
```
$ cat a.txt | tail -n 1
```
或
```
$ cat a.txt | tail -1
```
取得a.txt從第2行到最後一行
```
$ cat a.txt | tail +2
```
##### sort
以時間排序檔案清單
```
$ ls -l | sort -k 7
```
先排序檔案內容後再將重複的資料行去掉
```
$ sort a.txt | uniq
```
|參數|說明|
|-|-|
|-b|忽略開頭空白|
|-f|忽略大小寫|
|-n|以數字為主|
|-k|以欄位排序|
##### cut 擷取資料
擷取a.txt每行的第2~10個字元
```
$ cut -c 2-10 a.txt
```
擷取以空白隔開的檔案的第1個欄位
```
$ cut -f 3 a.txt
```
> 不使用`-d`參數的話預設就是以空白當作分隔字元
擷取以逗號隔開的檔案的第3個欄位
```
$ cut-d, -f 3 a.txt
```
##### tr
將字串lowercase letters的小寫轉成大寫
```
$ echo "lowercase letters" | tr a-z A-Z
```
去除a.txt每一行的裡的test
```
$ cat a.txt | tr -d "test"
```
##### 桃園市Ubike即時資料
https://data.tycg.gov.tw/opendata/datalist/datasetMeta?oid=5ca2bfc7-9ace-4719-88ae-4034b9a5a55c
#### 資料欄位說明
|索引|欄位名稱|說明|
|-|-|-|
|0|sareaen|行政區英文名|
|1|sarea|行政區中文名|
|2|lng|經度|
|3|sna|中文站名|
|4|snaen|英文站名|
|5|bemp|空位數量|
|6|ar|中文地址|
|7|act|全站禁用狀態(0:禁用、1:啟用)|
|8|sno|站編號|
|9|aren|英文地址|
|10|tot|場站總停車格|
|11|_id|資料編號|
|12|sbi|場站目前車輛數量|
|13|mday|微笑單車各場站來源資料更新時間|
|14|lat|緯度|
> **資料來源:**
>
> https://data.gov.tw/dataset/137993
##### curl取得ubike資料
```
$ curl -s https://data.tycg.gov.tw/api/v1/rest/datastore/a1b4714b-3b75-4ff8-a8f2-cc377e4eaa0f?format=csv
```
#### 系統指令
取得系統名稱和版本
```
$ cat /etc/os-release
```
#### 將檔案變成可執行檔
1. 將指令透過編輯器寫入檔案,附檔名取名為`.sh`
2. 加上可執行的權限: `chmod +x {檔名.sh}`
3. 執行: `./{檔名.sh}`
## 2024-05-29
#### crontab
排程器、定時器,在指定的時間執行程式。
```
# ┌───────────── 分鐘 (0 - 59)
# │ ┌─────────── 小時 (0 - 23)
# │ │ ┌───────── 日 (1 - 31)
# │ │ │ ┌─────── 月份 (1 - 12)
# │ │ │ │ ┌───── 星期幾 (0 - 7,0和7是週日,6 是週六)
# │ │ │ │ │
* * * * * Your command
```
> **注意:**
> 帳號必須擁有sudo權限才可以設定cron
##### 設定每分鐘輸出 my cron到畫面上
```
*/1 * * * * echo "my cron $(date)" >> /home/test/cron.log
```
> **備註:**
> 格式化date:
> ###### yyyy-mm-dd
> $(date '+%Y-%m-%d')
>
> ##### yyyy-mm-dd HH:MM:SS
> $(date '+%Y-%m-%d %H:%M:%S')
>
> ##### current date directly
> $(date '+%Y-%m-%d')
##### 重新啟動cron
方法一:
```
sudo service cron reload
```
方法二:
```
/etc/init.d/cron reload
```
## 檔案系統權限介紹
#### 第一個字元代表這個檔案是『目錄、檔案或連結檔等等』:
- d: 目錄。
- -: 檔案。
- l: 連結檔(link file);
- b: 裝置檔裡面的可供儲存的周邊設備(可隨機存取裝置);
- c: 裝置檔裡面的序列埠設備,例如鍵盤、滑鼠(一次性讀取裝置)。
接下來的字元中,以三個為一組,且均為『rwx』 的三個參數的組合。
- r: 代表可讀(read)
- w: 代表可寫(write)
- x: 代表可執行(execute)。
> 這三個權限的位置不會改變,如果沒有權限,則會出現減號。
第一組為『檔案擁有者可具備的權限』。
第二組為『加入此群組之帳號的權限』。
第三組為『非本人且沒有加入本群組之其他帳號的權限』。
#### `chgrp` :改變檔案所屬群組
```
$ chgrp {新的群組名稱} {檔案名稱}
```
#### `chown` :改變檔案擁有者
```
$ chown {新的擁有者名稱} {檔案名稱}
```
#### `chmod` :改變檔案的權限
```
$ chmod 777 {檔案名稱}
```
## vim分頁
|指令|縮寫|描述|
|-|-|-|
|:tabedit .||在目前目錄開啟新的分頁|
|gt||切換到下一個分頁|
|gT||切換到上一個分頁|
## vim分割視窗
|指令|縮寫|描述|
|-|-|-|
|:terminal|:term|打開終端機(水平)|
|:vertical terminal|:vert term|打開終端機(垂直)|
|exit||關閉終端機|
|Ctrl-w, 方向鍵||在分割視窗之間移動|
|:split|:sp|將目前檔案視窗水平分割|
|:vsplit|:vsp|將目前檔案視窗垂直分割|
|:split {filename}|:sp {filename}|視窗水平分割並開啟其他檔案|
|:vsplit {filename}|:vsp {filename}|視窗垂直分割並開啟其他檔案|
|:new||開啟新的視窗水平分割|
|:vnew|:vsp|開啟新的視窗垂直分割|
|:only||僅保留目前視窗|
|:close||關閉目前視窗|
|:set scrollbind|:set scb|讓兩個視窗同步移動|
|:set scrollbind!|:set scb!|取消兩個視窗同步移動|
#### .vimrc
```
" 語法高亮度顯示
syntax on
" 設定背景亮度(bg)
set background=dark
" 顯示行號(nu)
set number
" 標記搜尋到的字串
set hlsearch
" 自動縮排
set autoindent
" 顯示目前游標的行號跟列號
set ruler
" 顯示編輯狀態
set showmode
" 顯示輸入的命令
set showcmd
" 設定註解的顏色
highlight Comment ctermfg=cyan
" 設定搜尋到的字串顏色
highlight Search term=reverse ctermbg=4 ctermfg=7
" 設定tab 鍵的字元數
set tabstop=4
" 設定縮排的字元數
set shiftwidth=4
" 將輸入的TAB自動展開成空格。開啟後要輸入TAB,需要Ctrl-V+TAB
set expandtab
" 高亮度顯示配對的括號
set showmatch
" 總是顯示狀態行
set laststatus=2
" 顯示游標目前的所在行
set cursorline
" 閃爍游標
set mouse=a
" 搜尋時忽略大小寫(ic)
set ignorecase
" Ctrl-S儲存檔案, 須先在進入VIM之前執行# stty ixoff -ixon
map <c-s> :w
" 調整水平視窗大小
nmap + <C-W>+
nmap - <C-W>-
" 調整垂直視窗大小
nmap < <C-w><
nmap > <C-w>>
" 設定netrw瀏覽視窗開啟檔案時開啟在上一個分割視窗中
let g:netrw_browse_split=4
```
## 系統管理指令
##### 查詢目前登入的帳號名稱
```
$ whoami
```
##### 新增使用者happy
```
$ sudo adduser happy --shell /bin/bash
```
##### 刪除使用者happy
```
$ sudo userdel happy
```
##### 查詢目前使用的shell
```
$ echo $SHELL
```
##### 查詢帳目前帳號屬於那些群組
```
$ groups
```
##### 查詢happy帳號屬於那些群組
```
$ groups happy
```
##### 修改密碼
```
$ passwd
```
##### 修改別人的密碼
```
sudo passwd aaron
```
> 修改別人密碼必須有系統管理者權限
##### 將happy帳號加入sudo群組,讓他擁有系統管理者權限
```
sudo usermod -aG sudo happy
```
##### 將happy從sudo群組移除
```
sudo deluser happy sudo
```
##### 直接將目前身分切換成root(Linux最高權限帳號)
```
$ sudo su
```
> 1. 必須是sudo群組內的帳號才有此能力
> 2. `exit`指令可以離開root帳號,回到原本帳號
##### 列出系統內全部帳號
```
$ cat /etc/passwd
```
## 透過ssh連線到Linux
1. 下載putty: https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html
2. 編輯OpenSSH設定檔
```
$ sudo vim /etc/ssh/sshd_config
```
3. 將`#PasswordAuthentication yes`第一個井字號刪除
4. `:wq`存檔離開
5. 重新啟動SSH服務: `$ sudo service ssh restart`
6. 查看IP位址: `$ ip a`
找到192.168.xxx.xxx的網址
7. 打開putty,並且在Host Name欄位輸入IP,點擊Open按鈕進行連線
> 第一次連線會詢問是否接受遠端伺服器憑證,選擇Accept即可。
8. 輸入帳號、密碼登入Linux
## How To Customize Bash Prompt in Linux: A Beginner's Guide
https://medium.com/@dpriyamuthuvel4/how-to-customize-bash-prompt-in-linux-a-beginners-guide-63613ec3cdc9
#### 步驟:
1. `$ vim .bashrc`
2. 在最下面新增:
```
PS1="=> "
```
3. `:wq` 離開vim
4. `$ source .bashrc`
## Q/A
1. 讓Command Prompt出現12小時制的時間
`\D{%r}`: displays 12 hour time in the HH:MM:SS AM/PM format.
2. 設定時區: `sudo timedatectl set-timezone Asia/Taipei`
## 2024-05-28 VIM基礎
<section class="special features">
<h3>基本操作</h3>
</section>
<h4>命令模式(Command Mode)</h4>
<div class="table-wrapper">
<table class="alt">
<thead>
<tr>
<th>命令</th>
<th>說明</th>
</tr>
</thead>
<tbody>
<tr><td>. </td><td>重覆上一個指令 </td></tr>
<tr><td>i </td><td>在游標位置進入編輯模式 </td></tr>
<tr><td>I </td><td>在游標行的第一個非空白字元進入編輯模式 </td></tr>
<tr><td>a </td><td>在游標位置後進入編輯模式 </td></tr>
<tr><td>A </td><td>在游標行的最後一個字元進入編輯模式 </td></tr>
<tr><td>o </td><td>向下新增一行,並進入編輯模式 </td></tr>
<tr><td>O </td><td>向上新增一行,並進入編輯模式 </td></tr>
<tr><td>cc </td><td>刪除游標行,並進入編輯模式 </td></tr>
<tr><td>[ESC] </td><td>取消指令或退出編輯模式 </td></tr>
<tr><td>>> </td><td>向右縮排 </td></tr>
<tr><td><< </td><td>向左縮排 </td></tr>
<tr><td>N>> </td><td>多行縮排,N行向右縮排 </td></tr>
<tr><td>N<< </td><td>多行縮排,N行向左縮排 </td></tr>
<tr><td>gg </td><td>移到第一行 </td></tr>
<tr><td>G </td><td>移到最後一行 </td></tr>
<tr><td>nG </td><td>移動到第n行 </td></tr>
<tr><td>0 </td><td>移動到該行最前面 </td></tr>
<tr><td>^ </td><td>移動到該行最前面非空白第一個字元處 </td></tr>
<tr><td>$ </td><td>移動到該行最後面 </td></tr>
<tr><td>n[SPACE] </td><td>向右移動 n 個字元 </td></tr>
<tr><td>n[ENTER] </td><td>向下移動 n 行 </td></tr>
<tr><td>yy </td><td>複製游標行 </td></tr>
<tr><td>yG </td><td>複製游標行到最後一行 </td></tr>
<tr><td>y1G </td><td>複製游標行到第一行 </td></tr>
<tr><td>y$ </td><td>複製游標處到最後一個字元 </td></tr>
<tr><td>y0 </td><td>複製游標處到第一個字元 </td></tr>
<tr><td>p </td><td>在下一行貼上複製或刪除的內容 </td></tr>
<tr><td>P </td><td>在上一行貼上複製或刪除的內容 </td></tr>
<tr><td>dd </td><td>刪除游標行 </td></tr>
<tr><td>x </td><td>刪除游標所在處之字元。在vim及elvis亦可用 Del 鍵。 </td></tr>
<tr><td>X </td><td>刪除游標前之字元。不可使用 Backspace 鍵。 </td></tr>
<tr><td>dw </td><td>刪除游標所在的單字(中文不適用) </td></tr>
<tr><td>dG </td><td>刪除游標行到最後一行 </td></tr>
<tr><td>d1G </td><td>刪除游標行到第一行 </td></tr>
<tr><td>d$ </td><td>刪除游標處到最後一個字元 </td></tr>
<tr><td>D </td><td>刪除游標處到最後一個字元 </td></tr>
<tr><td>d0 </td><td>刪除游標處到第一個字元 </td></tr>
<tr><td>J </td><td>將游標行與下一行合併 </td></tr>
<tr><td>u </td><td>還原上一步(Undo) </td></tr>
<tr><td>Ctrl-r </td><td>重做上一步(Redo) </td></tr>
<tr><td>r </td><td>取代游標所在處之字元。 </td></tr>
<tr><td>R </td><td>取代字元至按 Esc 為止。 </td></tr>
<tr><td>Ctrl-f </td><td>往下翻一頁。 </td></tr>
<tr><td>Ctrl-b </td><td>網上翻一頁。 </td></tr>
<tr><td>Ctrl-d </td><td>往下翻半頁。 </td></tr>
<tr><td>Ctrl-u </td><td>網上翻半頁。 </td></tr>
<tr><td>Ctrl-e </td><td>往下滾一行。 </td></tr>
<tr><td>Ctrl-y </td><td>網上滾一行。 </td></tr>
<tr><td>zz </td><td>將游標所在行顯示在畫面中間。 </td></tr>
<tr><td>zt </td><td>將游標所在行顯示在畫面最上面。 </td></tr>
<tr><td>zb </td><td>將游標所在行顯示在畫面最下面。 </td></tr>
<tr><td>== </td><td>對目前行做自動排版。 </td></tr>
<tr><td>n== </td><td>多行做自動排版。 </td></tr>
<tr><td>gg=G </td><td>全部自動排版。 </td></tr>
<tr><td>q: </td><td>顯示命令模式下的歷史紀錄視窗。(Enter或:q可以離開)</td></tr>
<tr><td>q[紀錄位置]</td><td>記錄鍵盤操作,再按一次q可以離開。 </td></tr>
<tr><td>@[紀錄位置]</td><td>執行記錄的鍵盤操作。(例:@m,執行記錄在m的鍵盤操作)。</td></tr>
</tbody>
</table>
## Insert Mode(編輯模式)
## Last Line Mode(底線命令模式)
<h4>命令模式(Command Mode)</h4>
<div class="table-wrapper">
<table class="alt">
<thead>
<tr>
<th>命令</th>
<th>縮寫</th>
<th>說明</th>
</tr>
</thead>
<tbody>
<tr><td>:set (no)number </td><td>(no)nu </td><td>(取消)顯示行號</td></tr>
<tr><td>:set (no)ruler </td><td> </td><td>(取消)顯示目前的行號跟列號</td></tr>
<tr><td>:set (no)showcmd </td><td> </td><td>(取消)在狀態列顯示正在輸入的指令</td></tr>
<tr><td>:set (no)autoindent </td><td>(no)ai </td><td>(取消)按Enter換行時自動縮排</td></tr>
<tr><td>:set (no)cindent </td><td>(no)ci </td><td>(取消)類似C語言的縮排</td></tr>
<tr><td>:set (no)smartindent </td><td>(no)si </td><td>(取消)基於autoindent的一些改進</td></tr>
<tr><td>:set (no)wrap </td><td> </td><td>(取消)單行超過螢幕時自動換行顯示</td></tr>
<tr><td>:set (no)cursorline </td><td> </td><td>(取消)高亮顯示游標所在行</td></tr>
<tr><td>:set (no)cursorcolumn</td><td> </td><td>(取消)高亮顯示游標所在該列</td></tr>
<tr><td>:syntax on(off) </td><td> </td><td>語法高亮</td></tr>
<tr><td>:set tabstop=X </td><td>ts </td><td>一個TAB字元佔X個空格的位置。</td></tr>
<tr><td>:set shiftwidth=X </td><td>sw </td><td>文件的空格數。</td></tr>
<tr><td>:set (no)expandtab </td><td>(no)et </td><td>(取消)將輸入的TAB自動展開成空格。開啟後要輸入TAB,需要Ctrl-V+TAB</td></tr>
<tr><td>:retab </td><td> </td><td>在設定expandtab後,用Space取代原本在檔案文件中Tab</td></tr>
<tr><td>:set softtabstop=X </td><td>sts </td><td>方便在開啟了expandtab後使用退格(backspace)鍵,每次退格將刪除X個空格</td></tr>
<tr><td>:set (no)smarttab </td><td>(no)sta</td><td>(取消)在行首按TAB將加入sw個空格,否則加入ts個空格。</td></tr>
<tr><td>:DoMatchParen </td><td> </td><td>打開配對的括號高亮顯示</td></tr>
<tr><td>:NoMatchParen </td><td> </td><td>關閉配對的括號高亮顯示</td></tr>
<tr><td>:set (no)ignorecase </td><td>(no)ic </td><td>搜尋時不分大小寫</td></tr>
<tr><td>:set (no)hlsearch </td><td> </td><td>將搜尋到的字串高亮顯示</td></tr>
<tr><td>:! </td><td> </td><td>執行linux 指令,並顯示執行結果</td></tr>
<tr><td>:shell </td><td> </td><td>直接跳回shell執行linux 指令,輸入exit回vim</td></tr>
<tr><td>:w </td><td> </td><td>存檔 (加 ! 表示強制存檔)</td></tr>
<tr><td>:wa </td><td> </td><td>將所有檔案存檔</td></tr>
<tr><td>:w {filename} </td><td> </td><td>另存新檔</td></tr>
<tr><td>:wq </td><td> </td><td>存檔並退出 vi</td></tr>
<tr><td>:x </td><td> </td><td>存檔並退出 vi</td></tr>
<tr><td>:e {filename} </td><td> </td><td>編輯其它檔案</td></tr>
<tr><td>:e! </td><td> </td><td>還原至檔案編修前的狀態</td></tr>
<tr><td>:r {filename} </td><td> </td><td>讀入檔案內容,並加到游標行的後面</td></tr>
<tr><td>:n </td><td> </td><td>切換到下一個開啟的檔案</td></tr>
<tr><td>:N </td><td> </td><td>切換到上一個開啟的檔案</td></tr>
<tr><td>:files </td><td> </td><td>列出所有開啟的檔案</td></tr>
<tr><td>:q </td><td> </td><td>退出vi(加!表示強制退出)</td></tr>
<tr><td>:qa </td><td> </td><td>退出所有檔案(加!表示強制退出)</td></tr>
<tr><td>:E </td><td> </td><td>在目前視窗瀏覽目錄, 當前視窗檔案如有修改過, 將在上方開新視窗, 加!在左方</td></tr>
<tr><td>:cd [路徑] </td><td> </td><td>改變當前目錄</td></tr>
<tr><td>:pwd </td><td> </td><td>顯示目前所在路徑</td></tr>
<tr><td>:textwidth </td><td>tw </td><td>一行文字的寬度</td></tr>
<tr><td>:center </td><td>ce </td><td>本行文字置中。(是參考textwidth(tw) 的設定)</td></tr>
<tr><td>:left </td><td>le </td><td>本行文字靠左。(是參考textwidth(tw) 的設定)</td></tr>
<tr><td>:right </td><td>ri </td><td>本行文字靠右。(是參考textwidth(tw) 的設定)</td></tr>
<tr><td>:%! xxd </td><td> </td><td>使用十六進位方式編輯檔案</td></tr>
<tr><td>:%! xxd -r </td><td> </td><td>從十六進位編輯模式返回成文字模式</td></tr>
<tr><td>:r! {shell} </td><td> </td><td>執行Shell指令,並將結果加在游標行的後面。</td></tr>
<tr><td>:Ve </td><td> </td><td>在畫面左方開始視窗瀏覽目錄。</td></tr>
<tr><td>:Ve! </td><td> </td><td>在畫面右方開始視窗瀏覽目錄。</td></tr>
</tbody>
</table>
## 2024-05-27 Linux基礎
##### Linux發布版本
- CentOS: RedHat已不再維護
- Ubuntu: 架設伺服器的好選擇
- Debian: CentOS的祖先
- Slackware: 老牌Linux
- RedHat: 收費的Linux
##### 一般Linux和Embedded Linux的差別
- Embedded Linux能用的系統資源很小(成本問題)
(效能低、儲存空間小)
- Embedded Linux會移除用不到的系統功能
- 一般Linux通常有完整功能,安裝在電腦上
##### Linux shell
Bash: 透過Bash執行指令可以用來操作Linux所有功能
##### VMware workstation Pro開放免費
https://www.ithome.com.tw/news/162908
##### VWware Workstation Pro下載
https://support.broadcom.com/group/ecx/productfiles?subFamily=VMware%20Workstation%20Pro&displayGroup=VMware%20Workstation%20Pro%2017.0%20for%20Windows&release=17.5.2&os=&servicePk=520398&language=EN
##### 下載Ubuntu 24 LTS映像檔
https://ubuntu.com/download/server
> 備註:
> LTS(Long-term Support): 長期支援版,建議下載這個種版本的Linux
#### Linux基本指令
Linux大小寫為不同指令
##### `ls`
列出目前目錄下的所有檔案和目錄
##### `ls -l`
詳細列出目前目錄下的所有檔案和目錄資訊
##### `touch {檔名}`
建立一個新檔案,內容為空
##### `pwd`
顯示目前所有目錄
##### `echo Hello Ubuntu`
將Hello Ubuntu字串顯示到畫面上
##### `echo "Hello Ubuntu" > hello.txt`
將Hello Ubuntu字串重新導向到hello.txt檔案內
##### `cat hello.txt`
顯示hello.txt的檔案內容
##### `echo "Hello Ubuntu" >> hello.txt`
將Hello Ubuntu字串重新導向到hello.txt檔案內,接續原本的內容
##### `echo "Hello Ubuntu" | tr -d "\n" >> a.txt`
將Hello Ubuntu的換行符號使用管線丟給tr指令去掉後再導向到a.txt內
##### `printf "aaron Test1\naaron Test2\naaron Test3\naaron Test4\naaron Test5\n" > a.txt`
產生一個下面檔案:
```
aaron Test1
aaron Test2
aaron Test3
aaron Test4
aaron Test5
```
##### `cat a.txt | tr -d "aaron " > b.txt`
將a.txt檔案內的aaron字串刪除掉並存到b.txt內
> **補充:**
> 如果導向的檔案跟cat檔案相同檔名,則檔案內容會消失。
##### `mkdir test`
建立test目錄
##### `cd test`
切換到test目錄下
##### `rm hello.txt`
刪除hello.txt檔案
##### `rmdir test`
刪除test目錄
> **注意:**
> 目錄必須為空
##### `rm -rf test`
刪除test目錄和該墓錄下所有的檔案和子目錄
> **注意:**
> 該語法十分暴力且無法復原,請小心使用
##### `rm *.txt`
刪除所有附檔名為`.txt`的檔案
##### `mv a.txt b.txt`
將a.txt改名成b.txt
##### `history`
顯示輸入果的指令紀錄
##### `history | more`
用分頁的方式顯示超過一個畫面的資料
- ENTER: 下一行
- SPACE: 下一頁
- Q: 離開
##### `!!` or `!-1`
執行上一個指令
##### `!-2`
執行上兩個指令
##### `!100`
執行history編號100的指令
##### `history | head -n 5`
顯示history的前5筆資料
##### `history | tail -n 5`
顯示history的最後5筆資料
##### `printf !10` or `history | head -n 10 | tail -n 1`
顯示history第10筆資料
##### vim編輯檔案
1. `vim a.txt`
2. i
3. :wq
# 大標題
## 2024-05-27
這是文件內容
- 清單
1. 有序清單
2. 有序清單
```python=
i = 99
for i in a:
print('Hello')
```
> **備註:**
> 這段程式碼很厲害
[這是google搜尋](https://google.com/)
![圖片](https://www.nagasaki-tabinet.com/storage/special_features/276/responsive_images/bLSMpZQoOMOy6dnhlxAlWc4Gx4ajNpRNpD47FgfV__1639_1092.jpeg)
- [ ] 這是打勾清單
- [x] fjfjfjjf
<img src="https://www.nagasaki-tabinet.com/storage/special_features/276/responsive_images/bLSMpZQoOMOy6dnhlxAlWc4Gx4ajNpRNpD47FgfV__1639_1092.jpeg" width="50%" />