分類
發燒車訊

衣索比亞總理阿邁德推動環保、性平獲2019年諾貝爾和平獎

貝爾和平獎11日出爐,得獎者是衣索比亞總理阿邁德(Abiy Ahmed),原因是他結束該國與鄰國厄利垂亞之間長達20年的戰火,這項創舉又激發了非洲地區一系列的外交突破,阿邁德也提倡性別平等、環境保護。

阿邁德2018年4月上任,是該國第1位奧羅莫元首,在最初幾個月,他果斷、大膽地釋放政治犯,並對他們受到的酷刑予以譴責,也釋放被監禁的記者,甚至與政治反對派、民間社會對談,討論改革問題,並邀請先前流亡的政黨人士返國,還針對安全、司法部門進行重大改革。

阿邁德也致力於性別、環保問題,例如在國境內植樹造林以遏制氣候變化的負面影響。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是  USB CONNECTOR   ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案 ?

分類
發燒車訊

BERT的前世今生

Transformer

Transformer來自論文: All Attention Is You Need

別人的總結資源:

  1. 谷歌官方AI博客: Transformer: A Novel Neural Network Architecture for Language Understanding
  2. Attention機制詳解(二)——Self-Attention與Transformer谷歌軟件工程師
  3. 放棄幻想,全面擁抱Transformer:自然語言處理三大特徵抽取器(CNN/RNN/TF)比較中科院軟件所 · 自然語言處理 /搜索 10年工作經驗的博士(阿里,微博);
  4. Calvo的博客:Dissecting BERT Part 1: The Encoder,儘管說是解析Bert,但是因為Bert的Encoder就是Transformer,所以其實它是在解析Transformer,裏面舉的例子很好;
  5. 再然後可以進階一下,參考哈佛大學NLP研究組寫的“The Annotated Transformer. ”,代碼原理雙管齊下,講得也很清楚。
  6. 《Attention is All You Need》淺讀(簡介+代碼)這個總結的角度也很棒。

A High-Level Look

可以將輸入的語言序列轉換成另外一種序列,比如下圖的神經機器翻譯:

Transformer模型由編碼器-解碼器組合組成,解碼器負責對序列進行編碼,提取時間和空間信息,解碼器負責利用時間和空間特徵信息進行上下文預測,下圖是單個結構:

編碼器和解碼器堆棧的組合結構,在谷歌的實驗結構中採用了6個編碼器和6解碼器相對應,使模型的編碼能力和解碼能力達到一個平衡狀態(堆棧式結構):

編碼器-解碼器的內部結構,類似seq2seq模型:

seq2seq模型:

Encoder: 由6個相同的層組成, 每層包含兩個sub-layers.第一個sub-layer就是multi-head attention layer,然後是一個簡單的全連接層。其中每個sub-layer都加了residual connection(殘差連接)和normalisation(歸一化)。

Decoder: 由6個相同的層組成,這裏的layer包含三個sub-layers, 第一個sub-layer 是masked multi-head attention layer。這裡有個特別點就是masked, 作用就是防止在訓練的時候,使用未來的輸出的單詞。比如訓練時,第一個單詞是不能參考第二個單詞的生成結果的。Masked是在點乘attention操作中加了一個mask的操作,這個操作是保證softmax操作之後不會將非法的values連到attention中,提高泛化性。

Self-Attention at a High Level

假設下面的句子就是我們需要翻譯的輸入句:

”The animal didn’t cross the street because it was too tired”

當模型處理單詞的時候,self attention層可以通過當前單詞去查看其輸入序列中的其他單詞,以此來尋找編碼這個單詞更好的線索。

Self-Attention in Detail

第一步是將輸入的嵌入詞向量通過三個不同的參數矩陣得到三個向量,分別是一個Query向量,一個Key向量和一個Value向量,參數矩陣分別為Wq,Wk,Wv,,如下圖所示:

第二步是通過當前詞的q向量與其他詞的k向量計算當前詞相對於其他詞的得分,分數採用點積進行計算,如下圖所示:

第三步和第四步是講得到的分數除以k值維數的平方根(k值維數為64,可以使訓練過程有更加穩定的梯度,這個歸一化的值是經驗所得),再通過softmax得到每個得分的標準化得分:

第五步是對當前詞所得到的標準化值對所有value向量進行加權求和得到當前詞的attention向量,這樣就使不同單詞的嵌入向量有了attention的參与,從而預測上下文句子的時候體現不同的重要的重要程度。

Matrix Calculation of Self-Attention

  • Attendtion向量計算的矩陣形式,通過全職矩陣進行詞向量的計算大大加快了神經網絡的速度

  • X矩陣中的每一行對應於輸入句子中的一個單詞。(圖中的4個方框論文中為512個)和q / k / v向量(圖中的3個方框論文中為64個)

公式中濃縮前面步驟2到5來計算self attention層的輸出。

The Beast With Many Heads

使用“Multi-headed”的機制來進一步完善self-attention層。“Multi-headed”主要通過兩個方面改善了Attention層的性能,參數組成和子空間映射:

Many Heads的優缺點:

  • 它拓展了模型關注不同位置的能力。Multi head 的每個參數矩陣都會記錄單詞的位置信息,使原來的單個位置信息變得更加複雜。

  • 它為attention層提供了多個“representation subspaces”。由下圖可以看到,在self attention中,我們有多個個Query / Key / Value權重矩陣(Transformer使用8個attention heads),使特徵的提取變得更加複雜,而不是作為一個整體的特徵進行,每個單獨的子空間都會進行上下文的信息融合

在8個不同的子空間進行self-attention的操作,每個單詞生成獨立的8個向量

將8個子空間生成的向量壓縮成一個大向量,每個向量的子空間矩陣能夠學習到更多細節,壓縮過程採用一個更大的參數矩陣進行,對multi-head向量進行組合,生成最終的特徵向量。

整體的框圖來表示一下計算的過程:

Representing The Order of The Sequence Using Positional Encoding

其實上面介紹的網絡裏面並沒有考慮序列的位置信息,在RNN中不同時刻的信息是通過遞歸網絡的時間t來刻畫的,有明顯的時間刻度,所以引入了位置向量來解決時間刻度問題。

為了讓模型捕捉到單詞的順序信息,添加位置編碼向量信息(POSITIONAL ENCODING),位置編碼向量不需要訓練,它有一個規則的產生方式,生成與詞嵌入向量有着相同的向量就可以。

通過構造函數sin、cos來對位置進行嵌入,pos為單詞位置信息,而i用來表達dimension 這裏為了好說明,如果2i= dmodel, PE 的函數就是sin(pos/10000)。這樣的sin, cos的函數是可以通過線性關係互相表達的,通過兩個函數對奇偶維度進行編碼。位置編碼的公式如下圖所示:

個人認為選擇正餘弦函數主要是在-1和1之間是一個對稱關係,兩個相鄰的維度編碼相差比較大,在位置上有更好的區分性,1000是序列的長度,一般盡量將取值範圍控制在四分一個周期裏面,這樣會使每一個序列的每一個維度都取唯一的值。

The Residuals

編碼器和解碼器裏面的每一層都採用殘差的思想進行訓練,目的就是為了解決網絡過深情況下的難訓練問題,殘差連接可以將目標值問題轉化成零值問題,一定程度也可以減少網絡的過擬合問題。

使用殘差連接的編碼器內部結構:

使用殘差連接的編碼器-解碼器內部結構:

The Decoder Side

通過自回歸方式進行預測,解碼器每一個時間步輸入一個單詞,然後輸出一個單詞,將預測的單詞作為下一時刻的輸入進行單詞的預測,直到預測結束。

The Final Linear and Softmax Layer

  • 線性層是一個簡單的全連接神經網絡,模型一次生成一個輸出,我們可以假設模型從該概率分佈中選擇具有最高概率的單詞並丟棄其餘的單詞。

  • 對於最終句子的生成有2個方法:一個是貪婪算法(greedy decoding),一個是波束搜索(beam search)。

Bidirectional Encoder Representation from Transformers

Word Embedding

  • 線性模型,主要是對高維空間進行映射,其實是對one-hot向量的空間轉換。

  • 通過神經網絡對輸入的詞進行映射,獲取詞向量,一般有cbow和skip-gram兩種方法,此方法訓練的詞向量與上下文無關,並沒有參考位置信息,只是對詞的有無進行參考,採用的是負採樣,預測的時候進行的是一個二分類器,模型認為只要在下文中找出正確的詞就認為是完成了任務。

尚未解決一詞多義等問題。比如多義詞Bank,有兩個常用含義,但是Word Embedding在對bank這個單詞進行編碼的時候,是區分不開這兩個含義的,因為它們儘管上下文環境中出現的單詞不同,但是在用語言模型訓練的時候,不論什麼上下文的句子經過word2vec,都是預測相同的單詞bank,而同一個單詞占的是同一行的參數空間,這導致兩種不同的上下文信息都會編碼到相同的word embedding空間里去。所以word embedding無法區分多義詞的不同語義,這就是它的一個比較嚴重的問題。

Embedding from Language Models(ELMO)

  • ElMO採用雙向的LSTM做上下文相關的任務,從前到后和後到前分別做一遍LSTM的encoding操作,從而獲得兩個方向的token聯繫。

  • Word Embedding本質上是個靜態的方式,所謂靜態指的是訓練好之後每個單詞的表達就固定住了,以後使用的時候,不論新句子上下文單詞是什麼,這個單詞的Word Embedding不會跟着上下文場景的變化而改變,所以對於比如Bank這個詞,它事先學好的Word Embedding中混合了幾種語義 ,在應用中來了個新句子,即使從上下文中(比如句子包含money等詞)明顯可以看出它代表的是“銀行”的含義,但是對應的Word Embedding內容也不會變,它還是混合了多種語義。

ELMO的本質思想是:

事先用語言模型學好一個單詞的Word Embedding,此時多義詞無法區分,不過這沒關係。在我實際使用Word Embedding的時候,單詞已經具備了特定的上下文了,這個時候我可以根據上下文單詞的語義去調整單詞的Word Embedding表示,這樣經過調整后的Word Embedding更能表達在這個上下文中的具體含義,自然也就解決了多義詞的問題了。所以ELMO本身是個根據當前上下文對Word Embedding動態調整的思路。

一樣的,在具體進行下游任務的時候,採用神經網絡參數微調的方法根據不同的詞的上下文環境對詞向量進行調整,從而得到同一詞的不同向量表示。

缺點:

  • LSTM的抽取能力遠遠落後於Transformer,主要是并行計算能力

  • 拼接方式融合雙向特徵能力偏弱

Bidirectional Encoder Representation from Transformers

BRET採用兩階段模型,首先是語言模型預訓練;其次是使用Fine-Tuning模式解決下游任務。在預訓練階段採用了類似ELMO的雙向語言模型,雙向指的是對於預測單詞的上文和下文是否參与,如果都參与預測那麼就是雙向,雙向容易導致自己看自己的問題,後面提出mask來解決

經過預訓練的BRET模型,其已經具備了豐富的詞向量特徵信息,然後將此詞向量信息與下游任務進行組合進行NLP下游任務,例如文本生成,文本分類。

如何能夠更好將BRET模型與下游任務進行改造是一個比較複雜的問題,再好的預訓練語言模型都要與下游的任務模型相結合才有好的效果, BRET的優勢在於可以自由根據預訓練模型進行單詞級別的任務和句子級的任務。

BRET模型的創新

就是論文中指出的Masked 語言模型和Next Sentence Prediction。而Masked語言模型上面講了,本質思想其實是CBOW,但是細節方面有改進。

Masked 語言模型:

  • 而Masked語言模型上面講了,本質思想其實是CBOW,但是細節方面有改進,掩蓋的同時,要輸出掩蓋的詞的位置,然後用真實詞來預測。
  • Mask LM主要是為了增加模型的魯棒性和實際性能,但是在訓練時使用mask過多會影響實際任務的表現,所以做了一些處理:隨機選擇語料中15%的單詞,把它摳掉,也就是用[Mask]掩碼代替原始單詞,然後要求模型去正確預測被摳掉的單詞。但是這裡有個問題:訓練過程大量看到[mask]標記,但是真正後面用的時候是不會有這個標記的,這會引導模型認為輸出是針對[mask]這個標記的,但是實際使用又見不到這個標記,這自然會有問題。為了避免這個問題, BRET改造了一下,15%的被選中要執行[mask]替身這項光榮任務的單詞中,只有80%真正被替換成[mask]標記,10%被狸貓換太子隨機替換成另外一個單詞,10%情況這個單詞還待在原地不做改動。這就是Masked雙向語音模型的具體做法。

Next Sentence Prediction:

  • 指的是做語言模型預訓練的時候,分兩種情況選擇兩個句子,一種是選擇語料中真正順序相連的兩個句子;另外一種是第二個句子從語料庫中拋色子,隨機選擇一個拼到第一個句子後面。
  • 我們要求模型除了做上述的Masked語言模型任務外,附帶再做個句子關係預測,判斷第二個句子是不是真的是第一個句子的後續句子。之所以這麼做,是考慮到很多NLP任務是句子關係判斷任務,單詞預測粒度的訓練到不了句子關係這個層級,增加這個任務有助於下游句子關係判斷任務。所以可以看到,它的預訓練是個多任務過程。這也是BRET的一個創新,一般用於句級任務。

Transformer&BERT總結

  • 首先是兩階段模型,第一階段雙向語言模型預訓練,這裏注意要用雙向而不是單向,第二階段採用具體任務Fine-tuning或者做特徵集成;

  • 第二是特徵抽取要用Transformer作為特徵提取器而不是RNN或者CNN;

  • 第三,雙向語言模型可以採取CBOW的方法去做(當然我覺得這個是個細節問題,不算太關鍵,前兩個因素比較關鍵)。 BRET最大的亮點在於效果好及普適性強,幾乎所有NLP任務都可以套用BRET這種兩階段解決思路,而且效果應該會有明顯提升。可以預見的是,未來一段時間在NLP應用領域,Transformer將佔據主導地位,而且這種兩階段預訓練方法也會主導各種應用。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

新北清潔公司,居家、辦公、裝潢細清專業服務

※推薦評價好的iphone維修中心

分類
發燒車訊

談談 Promise 以及實現 Fetch 的思路

Promise 是異步編程的一種解決方案。

Promise


/**
 * 屬性
 */
Promise.length
Promise.prototype

/**
 * 方法
 */
Promise.all(iterable)   // 所有成功觸發成功  任何失敗觸發失敗
Promise.race(iterable)  // 任意一個成功或失敗后觸發
Promise.reject(reason)
Promise.resolve(value)

/**
 * 原型
 */
Promise.prototype.constructor
//方法
Promise.prototype.catch(onRejected)
Promise.prototype.then(onFulfilled, onRejected)
Promise.prototype.finally(onFinally)

Promise 有三種狀態

  • pending: 初始狀態,既不是成功,也不是失敗狀態。
  • resolve: 意味着操作成功完成。(resoloved)
  • reject: 意味着操作失敗。

pending

pending 是初始狀態,執行 resolve/reject 會進入對應狀態,如果不執行,責一直為 pending 狀態

例如下面代碼,promise 將一直在 pending 狀態,不會執行 then/catch.

new Promise(function (resolve, reject) { })
  .then(res => console.log(res))
  .catch(err => console.log(err))

resolve

resolve 意味着操作成功完成, 如果有 .then,值會傳入 .then 的第一個參數函數里。

new Promise(function (resolve, reject) {
  resolve(1)
})
  .then(res => console.log(res))

then 的第一個參數是成功的回調,第一個參數的返回值會影響接下來鏈的去向。第一個參數的返回值一般有三種情況

  • 無返回值:會去執行下一個 .then ,沒有參數
  • 返回值非promise:調用下一個then的函數,參數為返回值
  • 返回值為promise:根據promise的執行結果,執行 下一個then/catch,如果一直是pending,則不執行下一個then/catch

例如想要在當前 then 終止,可以這樣操作:

  .then((res) => new Promise(() => {}))

reject

reject 意味着操作失敗。

使用 .catch 會捕獲到錯誤信息。

與代碼報錯(如 undefined.a)不同的是, 代碼報錯如果不使用 catch 捕獲,會向外傳遞,最終傳遞到根結點;而 reject 屬於 promise 錯誤,即使不使用 catch 捕獲也不會對全局有影響。

用 promise 實現 fetch

先來看幾個問題:

  1. 如果請求 code 404, 會走 then 還是 catch? (答案:then)
  2. 控制台能看到一行 404 的錯誤, 為什麼還是走 then 不是 catch 呢
  3. 如果請求跨域失敗,走 then 還是 catch?(答案:catch)
  4. 同樣是控制台看到錯誤,兩者有什麼區別呢?
  5. 跨域失敗的報錯, 和 then 中 undefined.a 報錯,如果都不 catch,後者在 react 腳手架開發環境頁面會蹦,兩者有什麼區別?

帶着這幾個問題,來看看 fetch。

fetch 返回值是 promise,所以有三種狀態 pending、resolve、reject.

  • pending: 請求中
  • resolve: 請求成功(code 200/404/500 等, 非 200 控制台輸出錯誤)
  • reject: 請求失敗(跨域失敗、連接超時、無網絡等,控制台輸出錯誤)

我們還發現,請求失敗時,只能 catch 到最後一行錯誤, 如圖

捕獲后

為什麼 404 在控制台看到錯誤,還走 then, resolve 如何實現

實現有幾個難點,

  1. throw 後面代碼不會執行;
  2. 先報錯,后執行 then;
  3. catch 后錯誤不會打印在控制台;

試了下,Promise.reject(‘xxx’) 這樣的報錯方式雖然是微觀任務,但是總是在.then之後才在控制台輸出,更像是宏觀任務。所以也加個setTImeout宏觀任務調至後面。

var fetch = function () {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      if ('請求成功 200') {
        resolve('Response數據結構');
      } else if ('請求成功 404,500等') {
        Promise.reject('GET xxxxxxxx 404');
        setTimeout(function () {
          resolve('Response數據結構');
        });
      }
    })
  })
}

請求失敗 例如跨域失敗 reject 如何實現呢

同樣加個 setTimeout

var fetch = function () {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      if ('請求成功 200') {
        resolve('Response數據結構');
      } else if ('請求成功 404,500等') {
        Promise.reject('GET xxxxxxxx 404');
        setTimeout(function () {
          resolve('Response數據結構');
        });
      } else if ('請求失敗') {
        Promise.reject('Access to fetch xxxxx with CORS disabled.');
        Promise.reject('GET xxxxx net::ERR_FAILED');
        setTimeout(function () {
          reject('TypeError: Failed to fetch');
        });
      }
    })
  })
}

還是有些問題,我們實現的因為在promise 中,錯誤會有前綴 Uncaught (in promise)。瀏覽器客戶端應該有更好的實現方式。

最後總結一下 fetch 的三種情況

  • pending: 請求中
  • resolve: 請求成功(code 200: 調用 resolve 返回數據; code: 404/500 等, 先拋錯,再調用 resolve 返回數據。)
  • reject: 請求失敗(跨域失敗、連接超時、無網絡等,先控制台拋錯,再調用 reject)

拋錯均不影響代碼執行,與 undefined.a 不同。

whosmeya.com

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※幫你省時又省力,新北清潔一流服務好口碑

※回頭車貨運收費標準

分類
發燒車訊

Docker(三)Docker常用命令

Docker常用命令

幫助命令

# 显示 Docker 版本信息
docker version  

# 显示系統信息,包括鏡像和容器的數量
docker info 

# 查看幫助文檔 幫助文檔地址:https://docs.docker.com/reference/
docker [命令] --help  

鏡像命令

查看最近創建的鏡像

docker images 查看最近創建的鏡像

docker images [OPTIONS] [REPOSITORY[:TAG]]

# 幫助文檔
[root@hwh1 ~]# docker images --help 
Usage:	docker images [OPTIONS] [REPOSITORY[:TAG]]
List images
Options:
  -a, --all             Show all images (default hides intermediate images)    显示所有鏡像
      --digests         Show digests                                           显示摘要
  -f, --filter filter   Filter output based on conditions provided             根據提供的條件過濾輸出
      --format string   Pretty-print images using a Go template                用 Go 模板打印出一個圖像
      --no-trunc        Don't truncate output                                  不截斷輸出
  -q, --quiet           Only show numeric IDs                                  只显示数字 ID

# 查看最近創建的鏡像
# REPOSITORY  鏡像的倉庫源
# TAG  鏡像的標籤
# IMAGE ID  鏡像的id
# CREATED  鏡像的創建時間
# SIZE  鏡像的大小
[root@hwh1 ~]# docker images   
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello-world         latest              bf756fb1ae65        5 months ago        13.3kB

# 查看所有鏡像
[root@hwh1 ~]# docker images -a
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello-world         latest              bf756fb1ae65        5 months ago        13.3kB

# 只显示数字 ID
[root@hwh1 ~]# docker images -q
bf756fb1ae65

搜索鏡像

docker search 搜索鏡像

docker search [OPTIONS] TERM

[root@hwh1 ~]# docker search --help 
Usage:	docker search [OPTIONS] TERM
Search the Docker Hub for images
Options:
  -f, --filter filter   Filter output based on conditions provided   根據提供的條件過濾輸出
      --format string   Pretty-print search using a Go template      用 Go 模板打印出一個圖像
      --limit int       Max number of search results (default 25)    搜索結果的最大值限制
      --no-trunc        Don't truncate output                       不截斷輸出


[root@hwh1 ~]# docker search mysql
NAME                              DESCRIPTION                                     STARS    OFFICIAL            AUTOMATED
mysql                             MySQL is a widely used, open-source relation…   9626

下載鏡像

docker pull 下載鏡像

docker pull [OPTIONS] NAME[:TAG|@DIGEST]

[root@hwh1 ~]# docker pull --help 
Usage:	docker pull [OPTIONS] NAME[:TAG|@DIGEST]
Pull an image or a repository from a registry
Options:
  -a, --all-tags                Download all tagged images in the repository      下載倉庫中標記所有的鏡像,拿來選擇版本
      --disable-content-trust   Skip image verification (default true)            跳過圖像驗證       
      --platform string         Set platform if server is multi-platform capable  如果服務器支持多平台,則設置平台
 -q, --quiet                   Suppress verbose output                           禁止詳細輸出              

# 下載鏡像
[root@hwh1 ~]# docker pull mysql
Using default tag: latest                     # 版本信息(默認不設置tag,則為最新版)
latest: Pulling from library/mysql           
8559a31e96f4: Pull complete                   # 分層下載,docker image 的核心,聯合文件系統
d51ce1c2e575: Pull complete 
c2344adc4858: Pull complete 
fcf3ceff18fc: Pull complete 
16da0c38dc5b: Pull complete 
b905d1797e97: Pull complete 
4b50d1c6b05c: Pull complete 
c75914a65ca2: Pull complete 
1ae8042bdd09: Pull complete 
453ac13c00a3: Pull complete 
9e680cd72f08: Pull complete 
a6b5dc864b6c: Pull complete 
Digest: sha256:8b7b328a7ff6de46ef96bcf83af048cb00a1c86282bfca0cb119c84568b4caf6          # 簽名
Status: Downloaded newer image for mysql:latest 
docker.io/library/mysql:latest                 # 真實地址

刪除鏡像

docker rmi 刪除鏡像

docker rmi [OPTIONS] IMAGE [IMAGE...]

[root@hwh1 ~]# docker rmi --help 
Usage:	docker rmi [OPTIONS] IMAGE [IMAGE...]
Remove one or more images
Options:
  -f, --force      Force removal of the image        強制刪除鏡像
      --no-prune   Do not delete untagged parents    不刪除未標記的父類


# 刪除指定鏡像
[root@hwh1 ~]# docker rmi mysql 
Untagged: mysql:latest
Untagged: mysql@sha256:8b7b328a7ff6de46ef96bcf83af048cb00a1c86282bfca0cb119c84568b4caf6
Deleted: sha256:be0dbf01a0f3f46fc8c88b67696e74e7005c3e16d9071032fa0cd89773771576
Deleted: sha256:086d66e8d1cb0d52e9337eabb11fb9b95960e2e1628d90100c62ea5e8bf72306
Deleted: sha256:f37c61ee1973b18c285d0d5fcf02da4bcdb1f3920981499d2a20b2858500a110
Deleted: sha256:e40b8bca7dc63fc8d188a412328e56caf179022f5e5d5b323aae57d233fb1069
Deleted: sha256:339f6b96b27eb035cbedc510adad2560132925a835f0afddbcc1d311c961c14b
Deleted: sha256:d38b06cdb26a5c98857ddbc6ef531d3f57b00e325c0c314600b712efc7ff6ab0
Deleted: sha256:09687cd9cdf4c704fde969fdba370c2d848bc614689712bef1a31d0d581f2007
Deleted: sha256:b704a4a65bf536f82e5d8b86e633d19185e26313de8380162e778feb2852011a
Deleted: sha256:c37206160543786228aa0cce738e85343173851faa44bb4dc07dc9b7dc4ff1c1
Deleted: sha256:12912c9ec523f648130e663d9d4f0a47c1841a0064d4152bcf7b2a97f96326eb
Deleted: sha256:57d29ad88aa49f0f439592755722e70710501b366e2be6125c95accc43464844
Deleted: sha256:b17c024283d0302615c6f0c825137da9db607d49a83d2215a79733afbbaeb7c3
Deleted: sha256:13cb14c2acd34e45446a50af25cb05095a17624678dbafbcc9e26086547c1d74

# 遞歸刪除(批量刪除)
[root@hwh1 ~]# docker rmi -f $(docker images -aq)
Untagged: hello-world:latest
Untagged: hello-world@sha256:6a65f928fb91fcfbc963f7aa6d57c8eeb426ad9a20c7ee045538ef34847f44f1
Deleted: sha256:bf756fb1ae65adf866bd8c456593cd24beb6a0a061dedf42b26a993176745f6b
# 已全部刪除
[root@hwh1 ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

容器命令

注:下載一個 centos 鏡像測試

新建容器並啟動

docker run 新建容器並啟動

[root@hwh1 ~]# docker pull centos
Using default tag: latest
latest: Pulling from library/centos
8a29a15cefae: Pull complete 
Digest: sha256:fe8d824220415eed5477b63addf40fb06c3b049404242b31982106ac204f6700
Status: Downloaded newer image for centos:latest
docker.io/library/centos:latest

docker run

[root@hwh1 ~]# docker run --help 
Usage:	docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
Run a command in a new container
Options:
      -d, --detach                     Run container in background and print 
                                          container ID                           後台方式運行
      --name string                    Assign a name to the container            容器名字,來區分容器
      -i, --interactive                Keep STDIN open even if not attached      使用交互方式,進入容器查詢內容
      -t, --tty                        Allocate a pseudo-TTY                     使用交互方式,進入容器查詢內容
      -p, --publish list               Publish a container's port(s) to the host 指定容器端口 
          -p 主機端口:容器端口
          -p 容器端口
          -p ip:主機端口:容器端口
          容器端口
      -P, --publish-all                Publish all exposed ports to random ports 隨機端口
      

# 啟動並進入容器,相當於一個小型虛擬機
[root@hwh1 ~]# docker run  -it centos /bin/bash
[root@af833bdd3acf /]# ls      # 基礎版 centos 很多命令都不完善
bin  etc   lib	  lost+found  mnt  proc  run   srv  tmp  var
dev  home  lib64  media       opt  root  sbin  sys  usr
[root@af833bdd3acf /]# exit    # 退出命令
exit

列出所有正在運行的容器

docker ps 列出所有正在運行的容器

docker ps [OPTIONS]

[root@hwh1 ~]# docker ps --help
Usage:	docker ps [OPTIONS]
List containers
Options:
  -a, --all             Show all containers (default shows just running)           列出所有的容器,包括正在運行和停止的
  -f, --filter filter   Filter output based on conditions provided                 
      --format string   Pretty-print containers using a Go template
  -n, --last int        Show n last created containers (includes all states)       列出最近運行的容器
                        (default -1)
  -l, --latest          Show the latest created container (includes all states)    显示最後創建的容器
      --no-trunc        Don't truncate output                                      不截斷輸出
  -q, --quiet           Only display numeric IDs                                   只显示数字 ID
  -s, --size            Display total file sizes                                   显示文件總大小


[root@hwh1 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
a0f986785f33        centos              "/bin/bash"         7 seconds ago       Up 5 seconds                            nervous_agnesi
[root@hwh1 ~]# docker ps -n=1
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
a0f986785f33        centos              "/bin/bash"         6 minutes ago       Up 6 minutes                            nervous_agnesi
[root@hwh1 ~]# docker ps -q
a0f986785f33

退出容器

exit             # 直接容器停止並退出
Ctrl + P + Q     # 不停止容器退出(快捷鍵)

刪除容器

docker rm 刪除容器

docker rm [OPTIONS] CONTAINER [CONTAINER...]

[root@hwh1 ~]# docker rm --help 
Usage:	docker rm [OPTIONS] CONTAINER [CONTAINER...]
Remove one or more containers
Options:
  -f, --force     Force the removal of a running container (uses SIGKILL)      強制刪除正在運行的容器
  -l, --link      Remove the specified link                                    刪除指定的鏈接
  -v, --volumes   Remove anonymous volumes associated with the container       刪除與容器關聯的匿名卷

[root@hwh1 ~]# docker rm af833bdd3acf      刪除已經停止的
af833bdd3acf
[root@hwh1 ~]# docker rm -f a0f986785f33   刪除正在運行的容器
a0f986785f33

# docker ps -a -q|xargs docker rm    # 刪除所有的容器,使用管道符

啟動和停止容器操作

docker start id       # 啟動
docker restart id     # 重啟
docker stop id        # 停止當前正在運行的容器
docker kill id        # 強制停止當前容器

[root@hwh1 ~]# docker start 7b28015cd7f6
7b28015cd7f6
[root@hwh1 ~]# docker restart 7b28015cd7f6
7b28015cd7f6
[root@hwh1 ~]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                   PORTS               NAMES
7b28015cd7f6        centos              "/bin/bash"         46 seconds ago      Up 9 seconds                                 unruffled_wiles
e2ff2fee0669        bf756fb1ae65        "/hello"            12 days ago         Exited (0) 12 days ago                       amazing_nightingale
690a9f41c7a8        bf756fb1ae65        "/hello"            12 days ago         Exited (0) 12 days ago                       zealous_blackwell
[root@hwh1 ~]# docker stop 7b28015cd7f6
7b28015cd7f6
[root@hwh1 ~]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS              NAMES
7b28015cd7f6        centos              "/bin/bash"         57 seconds ago      Exited (0) 2 seconds ago                      unruffled_wiles
e2ff2fee0669        bf756fb1ae65        "/hello"            12 days ago         Exited (0) 12 days ago                         amazing_nightingale
690a9f41c7a8        bf756fb1ae65        "/hello"            12 days ago         Exited (0) 12 days ago       

常用的其他命令

後台啟動容器

# docker run -d 鏡像名
[root@hwh1 ~]# docker run -d centos
9e34ebe17e41fb762f535ab21d81240b5fb4b105a44ed13c8813a8a8978f9b27
# 問題:
# docker ps -a,發現服務停止了
# 常見的坑:
# docker 容器使用後台運行,就必須要有要一個前台進程,docker發現沒有應用,就會自動停止

查看日誌

docker logs [OPTIONS] CONTAINER

[root@hwh1 ~]# docker logs --help
Usage:	docker logs [OPTIONS] CONTAINER
Fetch the logs of a container
Options:
      --details        Show extra details provided to logs                         显示額外的詳細信息
  -f, --follow         Follow log output                                           跟蹤日誌輸出
      --since string   Show logs since timestamp (e.g. 2013-01-02T13:23:37) or     從時間戳開始显示
                       relative (e.g. 42m for 42 minutes)
      --tail string    Number of lines to show from the end of the logs (default   日誌显示行數
                       "all")
  -t, --timestamps     Show timestamps                                             显示時間戳
      --until string   Show logs before a timestamp (e.g. 2013-01-02T13:23:37)     在時間戳之前显示日誌
                       or relative (e.g. 42m for 42 minutes)

查看容器中進程信息

docker top CONTAINER [ps OPTIONS]

[root@hwh1 ~]# docker top --help 
Usage:	docker top CONTAINER [ps OPTIONS]
Display the running processes of a container

# docker top 容器id
[root@hwh1 ~]# docker top 147f08710d27
UID                 PID                 PPID                C                   STIME   
root                76123               76105               0                   21:13  

查看鏡像的元數據

docker inspect [OPTIONS] NAME|ID [NAME|ID...]

[root@hwh1 ~]# docker inspect --help 
Usage:	docker inspect [OPTIONS] NAME|ID [NAME|ID...]
Return low-level information on Docker objects
Options:
  -f, --format string   Format the output using the given Go template          用 Go 模板打印出一個圖像
  -s, --size            Display total file sizes if the type is container      如果類型是容器的話,就显示容器大小
      --type string     Return JSON for specified type                         返回指定類型的 JSON 字符串

# 查看 centos 的元數據
[root@hwh1 ~]# docker inspect 147f08710d27
[
    {
        "Id": "147f08710d2732d81ee9ce2680a7cfad48cbd186e87e27b081d82c103a29f084",
        "Created": "2020-06-15T13:13:13.783652979Z",
        "Path": "/bin/bash",
        "Args": [],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 76123,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2020-06-15T13:13:15.632825635Z",
            "FinishedAt": "0001-01-01T00:00:00Z"
        },
        "Image": "sha256:470671670cac686c7cf0081e0b37da2e9f4f768ddc5f6a26102ccd1c6954c1ee",
        "ResolvConfPath": "/var/lib/docker/containers/147f08710d2732d81ee9ce2680a7cfad48cbd186e87e27b081d82c103a29f084/resolv.conf",
        "HostnamePath": "/var/lib/docker/containers/147f08710d2732d81ee9ce2680a7cfad48cbd186e87e27b081d82c103a29f084/hostname",
        "HostsPath": "/var/lib/docker/containers/147f08710d2732d81ee9ce2680a7cfad48cbd186e87e27b081d82c103a29f084/hosts",
        "LogPath": "/var/lib/docker/containers/147f08710d2732d81ee9ce2680a7cfad48cbd186e87e27b081d82c103a29f084/147f08710d2732d81ee9ce2680a7cfad48cbd186e87e27b081d82c103a29f084-json.log",
        "Name": "/dazzling_benz",
        "RestartCount": 0,
        "Driver": "overlay2",
        "Platform": "linux",
        "MountLabel": "",
        "ProcessLabel": "",
        "AppArmorProfile": "",
        "ExecIDs": null,
        "HostConfig": {
            "Binds": null,
            "ContainerIDFile": "",
            "LogConfig": {
                "Type": "json-file",
                "Config": {}
            },
            "NetworkMode": "default",
            "PortBindings": {},
            "RestartPolicy": {
                "Name": "no",
                "MaximumRetryCount": 0
            },
            "AutoRemove": false,
            "VolumeDriver": "",
            "VolumesFrom": null,
            "CapAdd": null,
            "CapDrop": null,
            "Capabilities": null,
            "Dns": [],
            "DnsOptions": [],
            "DnsSearch": [],
            "ExtraHosts": null,
            "GroupAdd": null,
            "IpcMode": "private",
            "Cgroup": "",
            "Links": null,
            "OomScoreAdj": 0,
            "PidMode": "",
            "Privileged": false,
            "PublishAllPorts": false,
            "ReadonlyRootfs": false,
            "SecurityOpt": null,
            "UTSMode": "",
            "UsernsMode": "",
            "ShmSize": 67108864,
            "Runtime": "runc",
            "ConsoleSize": [
                0,
                0
            ],
            "Isolation": "",
            "CpuShares": 0,
            "Memory": 0,
            "NanoCpus": 0,
            "CgroupParent": "",
            "BlkioWeight": 0,
            "BlkioWeightDevice": [],
            "BlkioDeviceReadBps": null,
            "BlkioDeviceWriteBps": null,
            "BlkioDeviceReadIOps": null,
            "BlkioDeviceWriteIOps": null,
            "CpuPeriod": 0,
            "CpuQuota": 0,
            "CpuRealtimePeriod": 0,
            "CpuRealtimeRuntime": 0,
            "CpusetCpus": "",
            "CpusetMems": "",
            "Devices": [],
            "DeviceCgroupRules": null,
            "DeviceRequests": null,
            "KernelMemory": 0,
            "KernelMemoryTCP": 0,
            "MemoryReservation": 0,
            "MemorySwap": 0,
            "MemorySwappiness": null,
            "OomKillDisable": false,
            "PidsLimit": null,
            "Ulimits": null,
            "CpuCount": 0,
            "CpuPercent": 0,
            "IOMaximumIOps": 0,
            "IOMaximumBandwidth": 0,
            "MaskedPaths": [
                "/proc/asound",
                "/proc/acpi",
                "/proc/kcore",
                "/proc/keys",
                "/proc/latency_stats",
                "/proc/timer_list",
                "/proc/timer_stats",
                "/proc/sched_debug",
                "/proc/scsi",
                "/sys/firmware"
            ],
            "ReadonlyPaths": [
                "/proc/bus",
                "/proc/fs",
                "/proc/irq",
                "/proc/sys",
                "/proc/sysrq-trigger"
            ]
        },
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/74794286462edce8a73f8e74239c0229d6cec3afac92f052951245d91e05c7cd-init/diff:/var/lib/docker/overlay2/ae0a1afad34903571dd0df8a39bc4bea93ccd793ae2f6185fa95385c18d56f05/diff",
                "MergedDir": "/var/lib/docker/overlay2/74794286462edce8a73f8e74239c0229d6cec3afac92f052951245d91e05c7cd/merged",
                "UpperDir": "/var/lib/docker/overlay2/74794286462edce8a73f8e74239c0229d6cec3afac92f052951245d91e05c7cd/diff",
                "WorkDir": "/var/lib/docker/overlay2/74794286462edce8a73f8e74239c0229d6cec3afac92f052951245d91e05c7cd/work"
            },
            "Name": "overlay2"
        },
        "Mounts": [],
        "Config": {
            "Hostname": "147f08710d27",
            "Domainname": "",
            "User": "",
            "AttachStdin": true,
            "AttachStdout": true,
            "AttachStderr": true,
            "Tty": true,
            "OpenStdin": true,
            "StdinOnce": true,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/bin/bash"
            ],
            "Image": "centos",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {
                "org.label-schema.build-date": "20200114",
                "org.label-schema.license": "GPLv2",
                "org.label-schema.name": "CentOS Base Image",
                "org.label-schema.schema-version": "1.0",
                "org.label-schema.vendor": "CentOS",
                "org.opencontainers.image.created": "2020-01-14 00:00:00-08:00",
                "org.opencontainers.image.licenses": "GPL-2.0-only",
                "org.opencontainers.image.title": "CentOS Base Image",
                "org.opencontainers.image.vendor": "CentOS"
            }
        },
        "NetworkSettings": {
            "Bridge": "",
            "SandboxID": "dcbcaf21dc6395481ce4c27bd58e83b306aee13216f852b4ac92edab13dc6698",
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "Ports": {},
            "SandboxKey": "/var/run/docker/netns/dcbcaf21dc63",
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "1b8456cbbb162e74762144d5a13305ba84acb45db92ce2467c0bc15724077b72",
            "Gateway": "172.17.0.1",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "172.17.0.2",
            "IPPrefixLen": 16,
            "IPv6Gateway": "",
            "MacAddress": "02:42:ac:11:00:02",
            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "23077e8fffbf9407b9d83e492e05cc11904b4dbf7fd3ab3a4b84c36c1a7ee4a5",
                    "EndpointID": "1b8456cbbb162e74762144d5a13305ba84acb45db92ce2467c0bc15724077b72",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.2",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:11:00:02",
                    "DriverOpts": null
                }
            }
        }
    }
]

進入當前正在運行的容器

# 我們通常容器都是使用後台方式運行的,需要進入容器,修改一些配置
# 方式一 :docker exec -it 容器id bashShell
# 進入容器后開啟一個新的終端,可以在裏面操作(常用)
# docker exec [OPTIONS] CONTAINER COMMAND [ARG...]

[root@hwh1 ~]# docker exec --help 
Usage:	docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
Run a command in a running container
Options:
  -d, --detach               Detached mode: run command in the background             在後台運行命令
      --detach-keys string   Override the key sequence for detaching a container      重寫用於分離容器的鍵序列
  -e, --env list             Set environment variables                                設置環境變量
  -i, --interactive          Keep STDIN open even if not attached                     即使沒有連接,也保持STDIN打開
      --privileged           Give extended privileges to the command                  授予命令擴展權限
  -t, --tty                  Allocate a pseudo-TTY                                    分配一個偽TTY
  -u, --user string          Username or UID (format: <name|uid>[:<group|gid>])       用戶名或者 id
  -w, --workdir string       Working directory inside the container                   容器內的工作目錄
  

[root@hwh1 ~]# docker exec -it a41c80fd6d1c /bin/bash
[root@a41c80fd6d1c /]# ls
bin  etc   lib	  lost+found  mnt  proc  run   srv  tmp  var
dev  home  lib64  media       opt  root  sbin  sys  usr


# 方式二 :docker attach 容器id
# 進入容器正在執行的終端,不會啟動新的終端
# docker attach [OPTIONS] CONTAINER

[root@hwh1 ~]# docker attach --help 
Usage:	docker attach [OPTIONS] CONTAINER
Attach local standard input, output, and error streams to a running container
Options:
      --detach-keys string   Override the key sequence for detaching a container       重寫用於分離容器的鍵序列
      --no-stdin             Do not attach STDIN                                       不要附加STDIN
      --sig-proxy            Proxy all received signals to the process (default true)  將所有接收到的信號代理到進程(默認為true)


[root@hwh1 ~]# docker attach a41c80fd6d1c
[root@a41c80fd6d1c /]# ls
bin  etc   lib	  lost+found  mnt  proc  run   srv  tmp  var
dev  home  lib64  media       opt  root  sbin  sys  usr

拷貝文件

# 從容器被拷貝文件到主機上
# docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-               docker cp 容器id:容器內路徑 目的的主機路徑

# 從主機上拷貝文件到容器
# docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH               docker cp 主機路徑 容器id:目的的容器內路徑

[root@hwh1 ~]# docker cp --help 
Usage:	docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-
    	docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH
Copy files/folders between a container and the local filesystem

Use '-' as the source to read a tar archive from stdin
and extract it to a directory destination in a container.
Use '-' as the destination to stream a tar archive of a
container source to stdout.

Options:
  -a, --archive       Archive mode (copy all uid/gid information)  存檔模式(複製所有uid/gid信息)
  -L, --follow-link   Always follow symbol link in SRC_PATH        始終遵循容器內路徑中的符號鏈接

# 從容器被拷貝文件到主機上
[root@hwh1 home]# docker attach a41c80fd6d1c
[root@a41c80fd6d1c /]# cd /home
[root@a41c80fd6d1c home]# ls
[root@a41c80fd6d1c home]# touch hwh.java               # 在 home 目錄下創建一個  hwh.java
[root@a41c80fd6d1c home]# ls
hwh.java
[root@hwh1 home]# ls
hwh  hwh1  hwh2  user01  user02
[root@hwh1 home]# docker cp a41c80fd6d1c:/home/hwh.java /home           # 將 hwh.java 複製到主機上
[root@hwh1 home]# ls
hwh  hwh1  hwh2  hwh.java  user01  user02

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

※教你寫出一流的銷售文案?

※超省錢租車方案

分類
發燒車訊

Java的前生今世

Java作為一門編程語言,自誕生以來已經流行了20多年,在學習它之前,我們有必要先了解一下它的歷史,了解它是如何一步步發展到今天這個樣子。

孕育

上世紀90年代,硬件領域出現了單片式計算機系統,比如電視機機頂盒這些消費設備。這些設備的特點是處理能力和內存都有限。如果使用C++編寫程序,則對於這類設備來說過於龐大。

所以需求便來了,為了適應這類設備,需要一種小型的計算機語言,Java便應運而生了。

1991年,Sun公司的James Gosling, Mike Sheridan和Patrick Naughton發起了一個名為“Green”的項目小組,主要用於電視機頂盒這類消費設備。

由於設備的處理能力和內存有限,所以要求語言短小、代碼緊湊。而對於電視機頂盒這類消費設備來說,廠商會選擇各種不同的CPU,所以要求語言可移植、不與特定的平台捆綁在一起

出生

Green項目組以C++為基礎,對C++進行了一些改造,並刪除了一些不太實用、複雜繁瑣的東西,開發出了名為“Oak”的語言,(Oka來自James Gosling辦公室外的橡樹)。

成長

挫折

1992年夏天,Green項目組已經能夠演示Green操作系統、Oak的程序設計語言、類庫和其硬件。

1992年9月,Green項目組發布了它的第一個名為“Start 7”的產品,該產品是一個個人数字助理設備,具有圖形界面和非常智能的遠程控制。

1992年11月,Green項目被剝離,成為Sun Microsystems的全資子公司Firstperson。

但是當時的硬件生產廠商對其項目並不感興趣,Firstperson花了一年多也沒找到希望購買其技術的買家。

1994年,First Person公司解散,被重新納入Sun公司。Oak語言無法進入市場,也被暫時擱置下來。

機遇

在上面的過程中,Internet的萬維網也在不斷髮展。對於客戶機/服務器模型來說,萬維網需要做的是將超文本頁面轉換到屏幕的瀏覽器中。

1994年6月到7月,Sun公司的團隊看到了互聯網的發展,一些圖形Web瀏覽器的出現讓他們認為互聯網可以演變成他們為有線電視所設想的相同的高度交互性媒體。經過三天的頭腦風暴后,該團隊將目標平台重新定位為萬維網平台。

1994年中期,Oak語言的開發者意識到他們可以開發一個瀏覽器,WebRunner瀏覽器誕生。

1995年,互聯網的發展帶給了Oak語言一個機遇。當時的網絡頁面是單調、死板的靜態頁面,業界希望頁面能夠“靈活”起來,並且希望代碼能夠通過網絡傳播進行跨平台運行。Oak的語言短小、可移植的特點和這些需求不謀而合。

Sun公司首先推出了可以嵌入網頁並且可以隨同網頁在網絡上傳輸的Applet(Applet是一種將小程序嵌入到網頁中進行執行的技術)。

設計者在設計WebRunner瀏覽器具有在網頁中執行內嵌代碼的能力,這種能力能讓網頁變得“靈活”。

同年,Sun公司將Oak更名為Java(因為Oak已經被使用了,Java一詞來自咖啡),WebRunner瀏覽器也演變成了HotJava瀏覽器,HotJava瀏覽器完全使用Java開發。

同年5月23日,Sun公司在Sun World會議上展示並正式發布了Java語言和HotJava瀏覽器,各大公司都紛紛停止了自己公司相關項目的開發,競相購買Java的使用許可證,併為自己的產品開發了相應的Java平台。

發展

1996年初,Sun公司發布了Java的第1個開發工具包(JDK1.0),這是Java發展的里程碑,標志著Java成為了一種獨立的開發工具。

同年9月,約8.3萬個網頁應用了Java來製作。

同年10月,Sun公司發布了Java平台的第1個即時編譯器。

但是人們很快意識到Java1.0並不能用來進行真正的應用開發。

1997年2月,JDK1.1面世,它彌補了JDK1.0的大多明顯缺陷,改進了反射能力,但是仍有局限性。

1998年12月,Sun公司發布了第二代Java平台——JDK1.2。此次發布有幾個不同的版本,分別是標準版J2SE、用於手機等嵌入式設備的微型版J2ME、用於服務器端處理的企業版J2EE。

此次發布是Java發展過程中最重要的里程碑,標志著Java的應用開始普及。

2000年5月,JDK1.3、JDK1.4、J2SE1.3相繼發布。

2001年9月,J2EE1.3發布。

2002年2月,J2SE1.4發布。該版本提高了Java的計算能力,擴展了標準類庫,提高了系統性能。

在此期間,Java Applet採用低調姿態,淡化了客戶端的應用,成為服務器端應用的首選平台

2004年9月,J2SE 1.5版本發布,該版本為重大更新,是自1.1版本以來第一個對Java語言做出重大改進的版本。JavaOne會議后,版本数字從1.5改為5.0。

2005年6月,Java SE 6發布。版本名稱發生了改變,如J2SE改為Java SE、J2ME改為Java ME、J2EE改為Java EE。該版本沒有對語言方面再進行改進,但是改進了其他性能,增強了類庫。

2006年11月,Sun公司將Java技術作為免費軟件對外發布。

2007年3月起,全世界所有開發人員均可對Java源代碼進行修改。

隨着數據中心越來越依賴於商業硬件而不是專用服務器,Sun公司在2009年被Oracle收購。

2011年,Oracle發布Java SE 7。

2014年,Java SE 8發布,近20年以來,該版本有了最大改變,Java 8提供了一種“函數式”編程方式,可以很容易地表述併發執行的計算。

2017年,Java SE 9發布。

Java 9之後,Oracle宣布每6月更新一次版本。

2020年3月,Java SE 14發布。

Java Web的發展

Java一路走來,為了適應時代發展,做出了許多改變。

在早期,Java是為了解決傳統的單機程序設計問題,但由於種種原因,Java後來轉向Web。

Web的最初模樣

Web為了提供交互性內容採取了客戶端/服務器系統,但是交互性完全由服務器提供。服務器產生靜態頁面,這些靜態頁面是事先寫好的,將其提供給能夠解釋並显示的客戶端瀏覽器。

但是我們的需求是千變萬化的,事先寫好的靜態頁面肯定不能滿足我們日益增長的需求。

CGI

CGI(Common Gateway Interfa,通用網關接口),它是一段程序,運行在服務器上,提供同客戶端HTML頁面的接口,通俗的講CGI就像是一座橋,把網頁和WEB服務器中的執行程序連接起來,它把HTML接收的指令傳遞給服務器,再把服務器執行的結果返還給HTML頁。

CGI使網頁變得不是靜態的,而是交互式的。

但是CGI程序的響應時間依賴於發送的數據量的大小、服務器和網絡的負載,一旦網站變得複雜起來,響應就會變得非常慢且難以維護。

Applet

Applet是一種將小程序嵌入到網頁中進行執行的技術,含有Applet的網頁的HTML文件代碼中部帶有<applet></applet>這樣一對標記,當支持Java的網絡瀏覽器遇到這對標記時,就將下載相應的小應用程序代碼並在本地計算機上執行該Applet。

在當時,Java Applet 可以大大提高Web頁面的交互能力和動態執行能力。

Java剛出現時,Applet是最受大家歡欣鼓舞的。但是由於當時的網絡環境的問題,安裝Java運行時環境(JRE)所需要的10MB帶寬對當時的用戶來說太過於恐怖。並且微軟的IE瀏覽器並並沒有包含JRE,所以Applet並沒有得到大規模應用。

Servlet

Servlet(Server+Applet),即服務器端小程序。Servlet能夠按照用戶提交的內容處理並返回相應的資源。可以輸出HTML頁面,動態展示數據。Servlet實現正確的接口就能夠處理Http請求。

但是出現了一個很大的問題:HTML代碼需要在Servlet類中用Java代碼一行一行輸出,表現、邏輯、控制、業務等全部在Servlet類中,造成Servlet類代碼混亂(HTML代碼、Java代碼都寫在一起),重複性高、閱讀性差、開發困難。

下面是使用Servlet在瀏覽器中輸出有一個h1標題的Hello World!字符串的HTML頁面。

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    PrintWriter out = response.getWriter();
    response.setContentType("text/html;charset=utf-8");
    out.println("<html>");
    out.println("<head>");
    out.println("<title>$Title$</title>");
    out.println("</head>");
    out.println("<body>");
    out.println("<h1>Hello World!</h1>");
    out.println("</body>");
    out.println("</html>");
}

可想而知,更複雜的頁面得寫多少代碼!

JSP

為了解決上面的問題,Sun公司開發出了JSP。

JSP(JavaServer Page)是一種動態網頁技術標準。JSP部署於網絡服務器上,可以響應客戶端發送的請求,並根據請求內容動態地生成HTML、XML或其他格式文檔的Web網頁,然後返回給請求者。JSP技術以Java語言作為腳本語言,為用戶的HTTP請求提供服務,並能與服務器上的其它Java程序共同處理複雜的業務需求。

可以將JSP頁面看成是一個能內嵌Java代碼的HTML頁面。

靜態部分(HTML頁面)是模板,可以提前寫好,動態部分(數據)可以由Java代碼動態生成。這樣一來就避免了在單純使用Servlet時HTML代碼和Java代碼都出現在Servlet類中的混亂情況。

JSP在運行時被轉換成Servlet,因此JSP本質是Servlet。

下面是使用JSP做和上面同樣的事情:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>
    <h1>Hello World!</h1>
  </body>
</html>

仍使用HTML模板,但不是用Java語句一行一行“堆”出來,這多方便!

使用了JSP后,雖然不用一行行地“堆”HTML頁面了,但是代碼混亂的問題仍沒有解決。表現、邏輯、控制、業務等代碼仍然寫在一塊了,只不過是從Servlet類中挪到JSP中了。

這樣混亂的代碼極不利於團隊開發,如果項目很小,那還能理順,但如果項目非常大的話,那就“剪不斷,理還亂了”。

所以這時候,我們急需將代碼分門別類的碼放整齊。

JSP + JavaBean(Model1模式)

JavaBean 是用Java語言寫成的可重用組件,JavaBean類要求:

  1. 類是公開的
  2. 具有私有成員變量
  3. 具有無參構造器
  4. 具有setter和getter方法

上面已經說了,單純使用JSP會有大量的HTML代碼和Java代碼耦合在一起,不利於開發、維護、分工協作。

我們舉一個登錄的例子:

登錄大致需要以下幾步:

  1. 在瀏覽器中輸入用戶名、密碼
  2. 獲取數據,交給服務器
  3. 把數據處理成合適的形式
  4. 查詢數據庫的用戶表,看是否有一條用戶名和密碼都符合輸入的記錄。如果有,則登錄成功。

單純使用JSP時,以上步驟全部在JSP登錄頁面中完成,該頁面既需要显示登錄表單、又需要獲取、處理數據、還需要查詢數據庫。太亂了!!

有了JavaBean,我們可以將JSP中大量重複的代碼抽取成可重用的組件,封裝成JavaBean,在一定程度上減輕了代碼的耦合度,也在一定意義上實現了分層

比如,用戶本身就是一個對象,我們可以將其抽取成JavaBean,數據的傳遞、查找都可使用JavaBean來完成。

JSP+Servlet+JavaBean(Model2模式——MVC模式)

上面介紹了Servlet、JSP、JSP+JavaBean,雖然在進步,但是都不盡如人意。那為什麼不讓它們結合起來取長補短?

我們之所以使用JavaBean,就是為了讓Java代碼和HTML代碼分離開了,而Servlet也是一個Java類,為什麼不使用它呢?

JSP+JavaBean已經實現了部分分層,使用MVC(Model-View-Controller)模式能進一步分層。

Model(模型):MVC模式的中心組件,處理數據和邏輯。(比如JavaBean,但不止只有JavaBean)

View(視圖):展示數據,渲染頁面。(前端頁面,比如HTML頁面、JSP頁面)

Controller(控制器):從View接收數據,向Model發送數據,即用於控制數據分發。(比如Servlet)

還用上面的登錄例子:

  1. 將JSP登錄頁面作為View

  2. Servlet類(Controller)用於接收用戶輸入的用戶名、密碼,將其封裝為用戶類(JavaBean),然後去數據庫中查詢。如果能查詢到則登錄成功。

  3. 將查詢結果返回給Controller,Controller根據查詢結果選擇一個合適的View,並將數據渲染到頁面,展示給用戶。(在本例中,如果查詢成功,則進入系統主頁;如果查詢不到,則用戶會看到一個登錄失敗頁面)

使用了MVC設計模式后,代碼有了明顯的分層,結構清晰,各司其職。

框架

為了減輕工作量,各種框架逐漸出現在人們的視野中。

所謂框架,可以把它看做一個半成品的項目/軟件,框架中有許多東西別人都已經幫我們寫好了,比如各種類、方法。

我們要做的就是去了解、學習框架,在寫好的框架的基礎上、遵循框架的制定好的規則、按照自己的思路、結合框架的思想、去開發我們自己的項目。

目前Java的Web開發中最出名的框架就是Spring家族了,比如SpringMVC、Spring、SpringBoot。

熟悉、利用這些框架能夠幫助我們快速、優雅地開發出符合需求的項目。

另,框架是別人寫好的輪子,有了它,我們能夠跑得更快,但是別忘了怎麼走。

總結

說了這麼多,相當於陪着Java從出生到現在走了一遍。我們可以看出Java的發展也不是一帆風順的,我認為Java之所以現在還這麼流行,原因之一就是它能夠一直保持更新,一直在根據時代的需求結合自身的特點不斷地做出改變。正如那句話「窮則變,變則通,通則達」。一門語言能做到這樣,身為人更應該要做到。

如有錯誤,還請指正。

參考資料:

  1. 百度百科
  2. 維基百科
  3. Java官方文檔
  4. Java核心卷一(第10版)
  5. Java編程思想(第4版)

文章首發於公眾號『行人觀學』

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

分類
發燒車訊

Linux-權限詳解

目錄

  • 前言
  • alias / unalias 命令別名
  • cd 切換目錄
  • cp 複製文件或目錄
  • cat 查看文件內容
  • chage 設置密碼有效期
  • chown 更改文件所屬
  • chmod 設置文件rwx權限
  • chattr / lsattr 隱藏屬性
  • crontab 定時任務
  • df 磁盤使用情況
  • date 系統時間 / hwclock 硬件時鐘
  • diff 文件比較
  • echo 標準輸出
  • find / locate 文件搜索
  • free 查看內存使用
  • head 查看文件前面的內容
  • history 命令歷史
  • ip 網絡配置管理
  • kill 結束進程
  • ln 創建鏈接(快捷方式)
  • ls 查看目錄中的內容
  • less 分頁查看文件
  • mv 剪切 / 重命名 文件或目錄
  • mkdir 創建目錄
  • ps 查看進程
  • pwd 显示當前目錄
  • passwd 修改密碼
  • rm 刪除文件或目錄
  • su 切換用戶
  • stat 查看文件詳細信息
  • sort 排序 / uniq 去重
  • split 分割文件
  • tar 打包
  • top 動態查看進程
  • tail 查看文件末尾內容
  • touch 修改文件的時間屬性或創建空文件
  • useradd / groupadd 用戶和組管理
  • vi / vim 文本編輯器
  • wc 統計字數行數
  • xargs 參數傳遞
  • yum 紅帽系列包管理工具
  • zip / unzip 壓縮與解壓

前言

  • 以下命令測試環境為CentOS7.8
  • 使用的shell為系統默認的bash
  • Linux下是區分大小寫的,這點和Windows不同
  • Linux大部分命令語法為命令 [選項] [參數],我所介紹的選項為常用選項並不包含全部

alias / unalias 命令別名

alias命令用於給指令設置一個別名,unalias命令用於取消設置

  • 可以給長命令起一個簡單的別名便於使用,如:

    alias ens33="vi /etc/sysconfig/network-scripts/ifcfg-ens33"
    
  • 取消已設置的別名命令

    unalias ens33
    
  • 可以避免危險操作,如系統默認的命令rm mv cp等,都是通過alias加了-i參數的

    # 查看所有的使用別名的命令
    [root@God ~]# alias  
    alias cp='cp -i'
    alias l.='ls -d .* --color=auto'
    alias ll='ls -l --color=auto'
    alias ls='ls --color=auto'
    alias mv='mv -i'
    alias rm='rm -i'
    
  • 在命令前加\或者使用命令全路徑可忽略使用別名

    # 不進行詢問直接刪除mail.log文件
    \rm /var/log/mail.log  
    或
    /usr/bin/rm  /var/log/mail.log
    
  • 在命令行通過aliasunalias設置或取消的別名都是暫時性的,僅作用於當前登錄的會話。如果想要永久生效,可以在~/.bashrc文件添加別名設置

cd 切換目錄

cd命令用於切換工作目錄至指定的目錄,可用相對路徑和絕對路徑

  • 選項

    • / 表示根目錄
    • . 表示當前目錄
    • .. 表示上一級目錄
    • - 表示上次所在的目錄
    • ~ 表示當前用戶的家目錄
    # 進入用戶家目錄
    cd ~
    
    # 進入指定目錄
    cd /etc
    
    # 進入上兩級目錄
    cd ../..
    

cp 複製文件或目錄

cp用來複制文件或目錄到指定位置

  • 語法

    cp [選項] 源 目標
    
  • 選項

    • -a 相當於同時指定-dpr
    • -d 複製時保留鏈接(相當於Windows系統中的快捷方式)
    • -p 保留源文件或目錄的屬性
    • -r|R 對目錄進行遞歸處理,複製目錄時必須加上它才能複製
    • -f 覆蓋已存在的目標而不給出提示
    • -i-f相反,如果目標文件存在,則提示是否覆蓋
    # 複製文件/etc/hosts到目錄/local下
    cp /etc/hosts /local
    
    # 複製文件/etc/hosts到目錄/local下並命名為hosts.bak
    cp /etc/hosts /local/hosts.bak
    
    # 複製目錄/etc到目錄/local下,如果/local/etc已存在直接覆蓋
    cp -af /etc /local
    
    # 複製目錄/etc到目錄/local下並重命名為etc.bak
    cp -a /etc /local/etc.bak
    

cat 查看文件內容

cat命令適合查看少量內容,並可將多個文件連接到一起進行標準輸出,當文本數據內容量過大時,推薦使用lessmore進行查看

  • 語法

    cat [選項] 文件1 [文件2 文件N]
    
  • 選項

    • -n 輸出時显示行號
    • -s 當遇到有連續兩行以上的空白行,就替換成一個空白行
    # 查看resolv.conf的內容
    cat /etc/resolv.conf
    
    # 將/etc/resolv.conf和/etc/hosts兩個文件連接到一起進行標準輸出,並显示行號
    cat -n /etc/resolv.conf  /etc/hosts
    
  • cat還可以配合重定向將標準輸入寫到文件中

    [root@God ~]# cat > demo.txt << EOF
    > 我在命令行打上 cat > demo.txt << EOF
    > 在 > 後面寫的東西都能寫入到文件中
    > 寫完了所有內容后,在最後單獨寫個EOF就可以了
    > EOF
    [root@God ~]# cat -n demo.txt 
         1	我在命令行打上 cat > demo.txt << EOF
         2	在 > 後面寫的東西都能寫入到文件中
         3	寫完了所有內容后,在最後單獨寫個EOF就可以了
    

chage 設置密碼有效期

chage 命令本質是修改通過/etc/shadow文件中的內容來設置賬號密碼有效期限的

  • 語法

    chage [選項] 用戶
    
  • 選項

    • -l 列出用戶的當前設置
    • -d DATE DATE為日期,格式YYYY-MM-DD,即設置上次修改密碼的時間,設置為0則下次登錄時必須改密碼,設置為-1則密碼永不過期,密碼是否過期就是根據這個時間計算的
    • -E DATE DATE為日期,格式YYYY-MM-DD,設置賬號失效日期(對root慎用),設置為0則立即失效,設置為-1則永不失效
    • -M N N為天數,密碼有效期,即每過N天不修改密碼的話密碼就會過期
    • -m N N為天數,即距離上次修改日期N天後,才可以更改密碼,設置為0表示隨時可更改
    • -W N N為天數,即距離密碼過期日N天前開始發出警告信息
    • -I N N為天數,即如果一個密碼已過期N天,那麼該賬號將失效
    # 列出 jet 用戶的賬號密碼有效日期詳細信息
    chage -l jet
    
    # 使 jet 用戶下次登陸時必須修改密碼
    chage -d 0 jet
    
    # 設置 jet 用戶2020年8月8日賬號失效
    chage -E '2020-8-8' jet
    
    # 設置用戶至少每90天就需要改一次密碼,並在15天之前提醒
    chage -M 90 -W 15 jet
    

chown 更改文件所屬

chown命令可以更改Linux下文件或目錄的所屬用戶、所屬組,Linux下一切皆文件,而文件必須有所屬

  • 語法

    chown [用戶][:用戶組] 文件或目錄              
    
  • 選項

    • -R 遞歸處理,將指定目錄下所有文件及子目錄一併處理
    • -v 显示執行過程
    # 更改/local/myfile.txt的擁有者為root用戶
    chown root /local/myfile.txt
    
    # 更改/local/myfile.txt的群組的使用者為root組
    chown :root /local/myfile.txt
    
    # 更改/local/myfile.txt的擁有者為root用戶,群組的使用者為root組
    chown root:root /local/myfile.txt
    
    # 更改目錄/local的擁有者為root用戶
    chown -R root /local
    

chmod 設置文件rwx權限

chmod命令可用於更改文件的r讀、w寫、x執行權限, 通過ls -lstat命令可查看文件的權限-rw-r--r-- 第一位表示文件類型,后9位每三位為一組,分別表示所屬用戶、所屬組、其他用戶的權限。

  • 語法

    chmod [選項] rwx的權限分值 文件或目錄
    
    • 權限分值 r=4, w=2, x=1
    chmod [選項] 身份標識(+|-)(r|w|x) 文件或目錄
    
    • 身份標識 u=user所屬用戶 , g=group所屬組, o=other其他用戶, a=all(u+g+o)所有用戶
  • 選項

    • -R 遞歸處理,將指定目錄下所有文件及子目錄一併處理
    # 更改文件/local/myscript.sh的權限
    # 文件擁有者權限=7(r+w+x) 同組用戶權限=5(r+x) 其他用戶權限=5(r+x)
    chmod 755 /local/myscript.sh
    
    # 去掉其他用戶對文件/local/myscript.sh的寫權限
    chmod o-w /local/myscript.sh
    
    # 去掉其他用戶對文件/local/myscript.sh的寫權限,給同組用戶加上執行權限
    chmod o-w,g+x /local/myscript.sh
    
    # 更改目錄/local的權限
    chmod -R 754 /local
    

chattr / lsattr 隱藏屬性

chattr命令可以用來修改文件或目錄的隱藏屬性,只有root用戶可以使用

  • 語法

    chattr [選項] (+|-|=)屬性 文件或目錄
    
    • + 表示增加該屬性
    • - 表示去掉該屬性
    • = 表示去掉其他屬性,只保留該屬性
  • 選項

    • -R 遞歸處理,將指定目錄下所有文件及子目錄一併處理
  • 屬性

    • a 設置后只能增加數據,而不能刪除或修改數據
    • i 設置后不能被刪除、改名、設定鏈接也無法新增,相當於鎖定
    • s 徹底刪除的屬性,即有該屬性的文件刪除后無法恢復
    • u 當一個應用程序請求刪除這個文件,系統會保留其數據塊以便以後能夠恢復,預防意外刪除
    # 給test.txt文件添加a屬性,使其只能增加數據
    chattr +a /local/test.txt
    
    # 去掉改屬性
    chattr -a /local/test.txt
    

lsattr 命令可以查看隱藏屬性

  • 語法

    lsattr [選項] [文件或目錄]
    
  • 選項

    • -a 显示隱藏文件
    • -d 显示目錄的屬性,而不是目錄中內容
    # 查看test.txt文件的隱藏屬性
    lsattr /local/test.txt
    
    # 查看/local目錄的隱藏屬性
    lsattr -d /local
    
    # 查看當前目錄下的文件或目錄的隱藏屬性,包含吟唱文件
    lsattr -a
    

crontab 定時任務

crontab命令用來管理需要周期性執行的任務,與Windows下的計劃任務類似,依賴於crond服務執行,定時任務的配置文件一般以用戶為單位,放在/var/spool/cron目錄中,執行日誌是/var/log/croncrontab通過cron 表達式來進行定時任務的配置

  • 避免資源分配不均勻,即多個定時任務在同一時間點執行時,盡量錯開
  • 取消不要的輸出選項,將執行結果 >> /dev/null中,避免一直發郵件
  • 一般情況下周與日、月不可同時共存
  • anacron是可喚醒關機期間的工作任務的配置,有檢測機制,針對不24小時開機的服務器,需要的自行百度
# cron表達式 分時日月周:
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  * user-name  command to be executed
# *    代表任何時刻
# ,    代表分隔時段
# -    代表時間範圍
# /N   N為数字,表示執行幾次
  • crontab 常用命令

    # 显示當前用戶crontab配置
    crontab -l
    
    # 編輯當前用戶crontab配置
    crontab -e
    
    # root用戶可以幫其他用戶新建/刪除crontab配置
    crontab -u guest
    
  • crontab 配置示例

    # 每1分鐘執行一次
    * * * * * echo $(date) >> /dev/null
    
    # 每5分鐘執行一次後面的命令
    */5 * * * * echo $(date) >> /local/my_crontab.txt
    
    # 每2小時執行一次後面的命令
    * */2 * * * echo $(date) >> /local/my_crontab.txt
    
    # 在3:00與10:00的時候執行一次
    * 3,10 * * * echo $(date) >> /local/my_crontab.txt
    
    # 在10:00到22:00之間每2小時執行一次
    * 10-22/2 * * * echo $(date) >> /local/my_crontab.txt
    
    # 在21:00到21:30之間每5分鐘執行一次
    0-30/5 21 * * * echo $(date) >> /local/my_crontab.txt
    
    # 每周一0點執行一次
    0 0 * * 1 echo $(date) >> /local/my_crontab.txt
    
    # 每年的5月20日00:00分都會給rose發一封情書郵件
    0 0 20 5 * mail rose < /home/jack/lover.txt
    

df 磁盤使用情況

df命令用於显示文件系統的磁盤使用信息

  • 語法

    df [選項] 
    
  • 選項

    • -h 以人類可讀的格式显示(K|M|G)
    • -i 显示inode文件的數量和使用量
    • -T 显示磁盤的文件系統類型
    # 显示磁盤使用情況
    df -h
    # 显示inode信息
    df -hi
    

date 系統時間 / hwclock 硬件時鐘

linux系統有兩個時鐘:一個是由主板電池驅動的硬件時鐘(Real Time Clock),也叫做RTC或者叫CMOS時鐘。當操作系統關機的時候,用這個來記錄時間,但是對於運行的系統是不用這個時間的;另一個時間是系統時鐘(System clock)也叫內核時鐘或者軟件時鐘,是由軟件根據時間中斷來進行計數的,內核時鐘在系統關機的情況下是不存在的,所以,當操作系統啟動的時候,內核時鐘是要讀取RTC時間來進行時間同步。並且在系統關機的時候將系統時間寫回RTC中進行同步。

date 命令比較常用,可以用來显示和設定系統的日期和時間,在显示方面還可以自定義格式

  • 語法

    date [+格式] [選項]
    
  • 格式

    • %Y 年 {0000..9999}
    • %m 月 {1..12}
    • %d 日 {01..31}
    • %H 時 {00..23}
    • %M 分 {00..59}
    • %S 秒 {00..59}
    • %N 納秒 {000000000..999999999}
    • %u 星期 {1..7}
    • %j 一年的第多少天 {001..366}
    • %F 完整的日期,相當於 %Y-%m-%d
    • %T 完整的時間,相當於 %H:%M:%S
    • %R 鐘錶上显示的時間, 相當於 %H:%M
    • %s 從1970-01-01 00:00:00 UTC 到現在的秒數
    # 格式化显示當前系統時間
    [root@God ~]# date "+%F %T.%N"
    2020-06-22 20:34:36.179451922
    
    # 显示今天是今年的第多少天
    [root@God ~]# date "+%j"
    174
    
    # 設置系統時間為2012-12-12 12:12:12
    [root@God ~]# date -s "2012-12-12 12:12:12"
    Wed Dec 12 12:12:12 CST 2012
    [root@God ~]# date
    Wed Dec 12 12:12:12 CST 2012
    
  • 選項

    • -d DATESTR 該選項非常強大,可以根據DATESTR的描述显示時間
    • -s DATESTR 根據DATESTR的描述,設置系統時間,把-d換成-s即可
    # 年year 月month 日day 時hour 分min 秒seconds 
    
    # 显示1天前的時間
    date -d "-1day"
    
    # 显示100天後的時間
    date "+%F %T" -d "+100day"
    
    # 显示新中國成立100周年是哪天
    date "+%F" -d "1949-10-01 +100year"
    # 設置日期為新中國成立100周年那天
    date "+%F" -s "1949-10-01 +100year"
    
  • 硬件時鐘hwclock的常用命令

    # 显示硬件時鐘時間
    hwclock
    
    # 將當前系統時間寫入硬件時鐘
    hwclock -w
    
    # 以系統時鐘為準,同步硬件時鐘
    hwclock --systohc
    
    # 以硬件時鐘為準,同步系統時鐘
    hwclock --hctosys
    
    # 將硬件時鐘設置成指定的時間
    hwclock --set --date="2008-08-08 08:08:08"
    
  • 使用ntpdate命令將本機時間與時間服務器的時間進行同步,沒有這個命令使用yum install ntpdate安裝

    # 將本機時間與阿里雲時間服務器時間進行同步 ntp[1-7].aliyun.com
    ntpdate ntp7.aliyun.com
    

diff 文件比較

diff命令可以快速比較兩個文件或目錄是否有不同

  • 語法

    # 比較文件
    diff [選項] 文件1 文件2
    # 比較目錄
    diff [選項] 目錄1 目錄2
    
  • 選項

    • -b 忽略一行當中僅有多個空白的區別(例如”about me”與”about me”視為相同)
    • -B 忽略空白行的區別
    • -i 忽略大小寫的區別
    # 比較兩個文件
    diff /etc/hosts /etc/hosts.bak
    

echo 標準輸出

echo命令用於打印字符串或變量的值,在shell腳本中極為常用,可以做出進度條效果,也可以打印彩色文字,詳情自行百度

  • 選項

    • -e 開啟轉義字符
    # 轉義:開啟與不開啟的區別
    [root@God test]# echo "Hello \n World"
    Hello \n World
    [root@God test]# echo -e "Hello \n World"
    Hello 
     World
     
    # echo 單引號與雙引號的區別
    [root@God test]# echo "$PATH"
    /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
    [root@God test]# echo '$PATH'
    $PATH
    
    [root@God test]# echo "Hello,World!"
    -bash: !": event not found
    [root@God test]# echo 'Hello,World!'
    Hello,World!
    

find / locate 文件搜索

find支持各種姿勢的查找方式,提供了相當多的查找條件,功能很強大。也正因如此它的選項也很多,有時使用起來也是比較耗費系統資源的,特別是直接從 / 下查找的時候,在實際使用中應盡量縮小查找目錄範圍,把/替換成你指定的查找路徑即可

  • 語法

    find [選項] 查找路徑 查找條件 動作
    
  • 選項

    • -L 跟隨符號鏈接,加上此選項意味着會搜索鏈接指向的目錄
  • 條件

    • -name NAME 根據名稱進行查找,支持通配符
    • -mtime +-DAY 根據修改時間按天查找。如+7代表7天(不含)前,-7代表7天(含)內
    • -mmin +-MIN 根據修改時間按分鐘查找。
    • -type TYPE 根據文件類型查找 TYPE的值有d目錄,f普通文件, l符號鏈接等
    • -size +-SIZE 根據文件大小查找。如+100M代表大於100MB的文件,-50M代表小於50MB的文件
    • -perm MODE 根據文件權限查找
    • -maxdepth N N為数字,表示查找深度
    • -user USER 根據用戶名查找
    • -uid UID 根據用戶ID查找
    • -gid GID 根據組ID查找
    • -empty 查找空文件或空目錄,即大小為0bytes
  • 動作

    • -delete 刪除查找出來的文件,目錄只能刪除空目錄
    • -ok CMD {} \; 交互式執行命令,每次執行前會詢問
    • -exec CMD {} \; 直接執行命令,不詢問
    • 說明
      • {} 表示的是查找出來的結果
      • ; 表示的是結束命令,因為;在各個系統中會有不同的意義,所以在前面的\是轉義字符,為了防止系統出錯。如果你不願意\,使用';'結束也是可以的
    # 查找下1層的目錄
    find / -maxdepth 1 -type d 
    
    # 查找下2層的目錄
    find / -maxdepth 2 -type d 
    
    # 根據名稱精確查找
    find / -name "restart_tomcat.sh"
    
    # 根據名稱模糊查找
    find / -name "*.log"
    
    # 根據修改時間查找
    find / -name "*.log" -mtime +7 
    
    # 查找是否有權限為777的文件
    find / -type f -perm 777 | xargs ls -l
    
    # 找到7天前的日誌文件,直接將其刪除
    find / -type f -name '*.log' -mtime +7 -delete
    
    # 找到7天前的日誌文件,並詢問是否將其刪除
    find / -type f -name '*.log' -mtime +7 -ok rm -rf {} \;
    
    # 找到7天前的日誌文件,直接將其刪除
    find / -type f -name '*.log' -mtime +7 -exec rm -rf {} \;
    
    # 使用 xrags 命令實現刪除
    find / -type f -name '*.log' -mtime +7 | xargs rm -rf
    

locate命令用來查找文件或目錄,要比find命令快很多,原因在於它不搜索具體目錄,而是通過/var/lib/mlocate/mlocate.db自身創建的數據庫進行搜索,這個數據庫含有本地所有文件信息。每天自動更新一次庫中的數據,有時剛創建的文件使用locate搜索不到時就是因為庫中的數據沒有及時更新,為了避免這種情況,在使用locate命令之前可以使用updatedb命令手動更新。如果沒有locate命令,則需要安裝一下yum -y install mlocate

  • 語法

    locate [選項] 查找條件    # 查找條件支持通配符和正則表達式
    
  • 選項

    • -c 只显示找到的數量
    • -i 忽略大小寫
    • -r 使用基礎正則表達式
    • --regex 使用擴展正則表達式
    # 使用前最好先更新一下數據庫
    updatedb
    
    # 查找包含 myfile 的文件和目錄
    locate myfile
    
    # 查找以myfile開頭的文件和目錄
    locate myfile*
    
    # 查找以myfile結尾的文件和目錄
    locate *myfile
    
    # 查找文件名為 1.txt 的文件
    locate -r "/1.txt$"
    

free 查看內存使用

free命令可以显示系統內存的使用情況,包括物理內存、交換內存(swap)和內核緩衝區內存

  • 語法

    free [選項]
    
  • 選項

    • -k 以KB為單位進行显示
    • -m 以MB為單位進行显示
    • -g 以GB為單位進行显示
    • -h 以人類可讀的格式显示(K|M|G)
    • -s N N為数字,表示間隔描述,用於持續觀察內存使用狀況
    # 3秒一刷新,显示內存使用情況
    free -h -s 3
    

head 查看文件前面的內容

head命令用於查看文件頭部或行內頭部的內容

  • 語法

    head [選項] 文件
    
  • 選項

    • -n N N為数字,表示前N行
    • -c N N為数字,表示行內的前N個字節。UTF-8編碼中一個字母佔1字節,一個漢字佔3字節
# 显示前100行內容
head -n 100 /local/

# 显示前5個字節的內容
echo "Hello,World" | head -c 5

history 命令歷史

history 命令用於記錄和显示你在命令行敲過的每一條命令,相鄰的重複命令默認會合併成一個。命令歷史記錄太多會讓系統變得不安全,可以根據自己的需求自定義以下環境變量進行限制

# 記錄命令歷史的文件
HISTFILE=/root/.bash_history
# 記錄命令歷史的文件最大記錄條數
HISTFILESIZE=1000
# 內存中命令歷史的最大記錄條數
HISTSIZE=1000
# 可以通過添加HISTTIMEFORMAT環境變量,記錄命令執行時間
HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S "
  • 語法

    history [選項] 
    
  • 選項

    • N N為数字,显示最近執行過的N條命令
    • -c 清空內存中的歷史命令
    • -rHISTFILE設置的文件中的內容讀取到內存
    • -w-r相反,把內存中的命令歷史寫入到文件中
    # 查看命令歷史
    history
    
    # 執行第66條命令
    !66
    
    # 執行上一條命令
    !!
    

ip 網絡配置管理

ip命令作為iproute2工具包的核心命令,它是linux下管理網絡和流量控制的工具包,旨在替代老牌的工具鏈net-tools,即ifconfig, arp, route, netstat等命令。net-tools通過procfs(/proc)ioctl系統調用去訪問和改變內核網絡配置,而iproute2則通過netlink套接字接口與內核通訊。拋開性能而言,net-tools的用法給人的感覺是比較亂,而iproute2的用戶接口相對net-tools來說相對來說,更加直觀。比如,各種網絡資源(如link、IP地址、路由和隧道等)均使用合適的對象抽象去定義,使得用戶可使用一致的語法去管理不同的對象。如今很多系統管理員依然通過net-tools配置管理網絡,但自2001年起,Linux社區已經對齊停止維護。同時,一些Linux發行版比如Arch Linux和CentOS/RHEL 7則已經完全拋棄了net-tools,只支持iproute2。如果你仍在使用net-tools,而且尤其需要跟上新版Linux內核中的最新最重要的網絡特性的話,那麼是時候轉到iproute2的陣營了。原因就在於使用iproute2可以做很多net-tools無法做到的事情。ip命令非常強大,如果要完全運用的話估計能寫一本書了。這裏就隨用隨加了,需要深入自行查閱官方文檔。

  • 語法

    ip [選項] 對象 {命令}
    
    • ip 命令的選項不支持連着寫,每個都要加-並用空格分隔
  • 選項

    • -c 加上顏色显示
    • -s 显示更多的信息
  • 對象

    • address IP協議設備
    • link 網絡設備
    • route 路由表
    • 所有對象的名稱均支持完整寫法和縮寫,如address可寫成addr add a
    # 查看IP地址
    ip -c addr
    

kill 結束進程

kill命令可以發送一個信號SIGTERM默認為15給進程,可將指定程序終止。程序或工作的編號可以利用ps命令和jobs命令查看

  • 語法

    kill -信號  進程ID|工作ID
    
  • 信號

    • 1 啟動被終止的進程,可讓該PID重新讀取自己的配置文件,類似重新啟動
    • 2 相當於用鍵盤Ctrl+c來中斷一個進程的進行
    • 9 強制中斷一個進程的執行,如果該進程進行到一半,那麼尚未完成的部分可能會有”半產品”產生,比如vim會有.filename.swp保留下來
    • 15 以正常的進程結束方式來結束進程
    • 17 相當於用鍵盤Ctrl+z來暫停一個進程的進行
    # 強制結束PID為8886的進程
    kill -9 8886
    
    # 強制結束JOBNUMBER為2的進程
    kill -9 %2
    
    # 強制結束所有的以httpd啟動的進程
    killall -9 httpd
    

ln 創建鏈接(快捷方式)

ln 命令可以為文件或目錄創建一個鏈接(link),鏈接可分為兩種:硬鏈接和軟鏈接。軟鏈接相當於windows下的快捷方式

  • 語法

    ln [選項] 源  目標
    
  • 選項

    • -s 創建為軟鏈接
    # 在家目錄下創建一軟連接
    ln -s /etc/sysconfig/network-scripts/ifcfg-ens33 ~/ifcfg-ens33
    

ls 查看目錄中的內容

ls命令用於显示指定工作目錄下之內容(列出目前工作目錄所含之文件及子目錄)。ll命令是系統自帶的一個別名命令,主要用於進行長列表显示內容

  • 語法

    ls [選項] [文件或目錄]
    
  • 選項

    • -a 显示所有內容,包括隱藏文件
    • -d 显示目錄本身,而不是目錄中的內容
    • -t 按照時間進行排序,最新的在最上面
    • -r 對排序進行翻轉
    • -l 使用長列表显示內容
    • -h 以人類可讀的格式显示(K|M|G)
    • --full-time 显示精確時間
    # 显示目錄下的所有內容
    ls -a 
    
    # 快速找到修改時間最新的文件,最下面那個就是
    ls -lrth
    

less 分頁查看文件

less是對文件或其他輸出進行分頁显示的工具,功能十分強大,而且不會一開始就加載整個文件,在性能和用法上比more更加的有彈性。使用less命令打開的內容可以使用各種功能按鍵來操作,個人感覺完全可以替代more,所以有人說less is more,相比於more,我更喜歡用less

  • 語法

    less [選項] 文件
    
  • 選項

    • -s 显示連續的空行為一個空行
    • -N 显示行號
    • -m 显示類似於more命令的百分比
    • -g 只標記最後搜索的關鍵詞
    • -i 搜索時忽略大小寫
  • 按鍵

    • h 查看幫助
    • ↑↓ 向上或向下一行
    • b 向上滾動一頁 PageUp
    • space 向下滾動一頁 PageDown
    • g 移動到第一行
    • G 移動到最後一行
    • N g/G N為数字,移動到第N行
    • q/Q 退出
    • / KEYWORD 進入向下搜索模式,可根據關鍵字進行搜索,n繼續往下找,N繼續往上找
    • & KEYWORD 輸入關鍵字,可僅显示包含關鍵字的行
    • F 類似於tail -f,實時讀取文件最新內容,按ctrl + c 停止
    # 使用 less 命令查看文件
    less -smN /etc/service
    
    # 使用 less 命令接收其他命令的標準輸出
    history | Dless
    

mv 剪切 / 重命名 文件或目錄

mv命令用來為文件或目錄重命名或移動文件或目錄(剪切)

  • 語法

    mv [選項] 源 目標
    
  • 選項

    • -i 若指定目錄已有同名文件,則先詢問是否覆蓋舊文件;
    • -f 如果目標存在,直接覆蓋不提示
    # 移動文件/local/hosts.bak到/local目錄下
    mv /etc/hosts.bak /local
    
    # 重命名文件hosts.bak為hosts
    mv /etc/hosts.bak /etc/hosts
    

mkdir 創建目錄

mkdir命令用來創建目錄

  • 語法

    mkdir [選項] 目錄
    
  • 選項

    • -m 創建目錄的同時設置權限
    • -p 如果父目錄不存在,則創建
    # 創建目錄/local/script,如果目錄/local不存在,會報錯
    mkdir /local/script
    
    # 創建目錄/local/script,如果目錄/local不存在,則創建
    mkdir -p /local/script
    
    # 創建目錄/local/script,如果目錄/local不存在,則創建,並給script目錄設定755的權限分數
    mkdir -pm 755 /local/script
    

ps 查看進程

ps命令用於显示當前進程的狀態,這個狀態是當前那些進程的快照,如果想要動態查看進程,請使用top命令,常用來通過管道命令搭配grep命令進行查詢,然後通過kill命令,刪除不需要的進程

  • 語法

    ps [選項]
    
  • 選項

    • -e 显示所有進程
    • -f 显示全格式列表,增加 UID、PPID、C與STIME欄位的显示
    # 根據關鍵字查找進程
    ps -ef | grep tomcat
    

pwd 显示當前目錄

pwd用於显示當前所在的路徑,加-P可显示真實路徑,而非鏈接路徑

[root@God /]# ll -d /sbin
lrwxrwxrwx. 1 root root 8 Jun 21 11:20 /sbin -> usr/sbin
[root@God /]# cd sbin/
[root@God sbin]# pwd    
/sbin
[root@God sbin]# pwd -P  
/usr/sbin

passwd 修改密碼

passwd可以用來更改用戶的密碼,還可以鎖定與解鎖用戶

  • 語法

    passwd [選項] 用戶
    
  • 選項

    • -d 刪除密碼
    • -f 強迫用戶下次登錄時必須修改密碼
    • -w 設置密碼到期前提前警告的天數
    • -l 鎖定賬戶
    • -u 解鎖賬戶
    • -x 設置密碼有效天數
    # 修改當前用戶的密碼
    passwd
    
    # 修改其他用戶的密碼,root用戶修改其他用戶密碼,不需要提供原密碼
    passwd jack
    
    # 鎖定用戶
    passwd -l jack
    
    # 解鎖鎖定的用戶
    passwd -u jack
    

rm 刪除文件或目錄

rm 用於刪除文件或目錄,生產服務器執行刪除命令前一定要備份

  • 語法

    rm [選項] 文件或目錄
    
  • 選項

    • -i 刪除前詢問
    • -f 直接刪除,不確認
    • -r 刪除目錄時使用,否則無法刪除目錄
    # 刪除目錄下所有內容,並且不經過確認,慎用
    rm -rf /local
    
    # rm 刪除目錄下所有隱藏文件
    rm /local/.*
    
    # rmdir 只能刪除空目錄,目錄不為空無法刪除
    rmdir /local
    

su 切換用戶

su命令用於切換當前用戶,除了root外,需要輸入該用戶的密碼

su命令和su -命令最大的本質區別就是:前者只是切換了root身份,但Shell環境仍然是普通用戶的Shell;而後者連用戶和Shell環境一起切換成root身份了。只有切換了Shell環境才不會出現PATH環境變量錯誤。su切換成root用戶以後,pwd一下,發現工作目錄仍然是普通用戶的工作目錄;而用su -命令切換以後,工作目錄變成root的工作目錄了。用echo $PATH命令看一下susu -以後的環境變量有何不同。以此類推,要從當前用戶切換到其它用戶也一樣,應該使用su -命令。

# 切換到用戶執行命令,命令執行完在自動切換回來
[root@God ~]# su jet -c ls
ls: cannot open directory .: Permission denied
[root@God ~]# su - jet -c ls
1.txt

stat 查看文件詳細信息

stat命令可以查看文件的詳細信息

  • 語法

    stat [選項] 文件
    
  • 選項

    • -c FORMAT 格式化显示 FORMAT的取值可以查看幫助
    # 查看文件的權限
    [root@God ~]# stat -c %A testfile 
    -rw-r--r--
    [root@God ~]# stat -c %a testdir/
    755
    

sort 排序 / uniq 去重

sort命令用於對文本內容或者是對其他命令的輸出進行排序显示。

  • 語法

    sort [選項] 文件
    
  • 選項

    • -u 合併重複的行
    • -r 反向排序
    • -g 按照数字大小排序
    • -t SEP 按照SEP進行分列,默認為空格
    • -k N N為数字,表示根據第N列排序
    # 根據進程號排序查看進程
    ps -ef | sort -rgk 2
    

uniq 命令用於去除重複的行,一般與sort搭配使用

  • 語法

    uniq [選項]  源數據
    
  • 選項

    • -c 統計重複行出現的次數
    • -d 僅显示重複出現的行
    • -u 僅显示出現一次的行
    # 統計IP地址出現的次數
    cat ip.txt | sort | uniq -c 
    

split 分割文件

split可以將大文件分割成若干個小文件

  • 語法

    split [選項] 文件 前綴
    
  • 選項

    • -d 給文件添加数字後綴
    • -b SIZE 根據大小進行分割,可以添加單位(b|k|m|g)等
    • -l N N為數字錶示行數,按照行數進行分割
    # 將catalina.out按照300m的大小進行分割,分割的文件會以catalog00,catalog01,catalog02的方式來建立
    split -db 300m catalina.out catalog
    
    # 將分割后的若干個小文件在還原
    more catalog* >> catalina.out
    

tar 打包

tar 命令用來打包或壓縮文件,選項相當多。一般只打包不壓縮的文件以.tar結尾,通過gzip進行打包壓縮的文件以.tar.gz結尾,通過bzip2進行打包壓縮的文件以.tar.bz2 結尾

  • 語法

    tar [選項] 壓縮文件名 操作目標
    
  • 選項

    • -c 創建打包文件
    • -x 釋放打包文件
    • -t 查看包文件內容
    • -v 显示詳細過程
    • -z 使用gzip的方式進行壓縮或解壓
    • -j 使用bzip2的方式進行壓縮或解壓
    • -h 同時打包鏈接指向的文件
    • -C 指定解壓目錄
    # 將目錄/local進行打包並使用gzip進行壓縮
    tar -zcvf local.tar.gz /local
    
    # 將local.tar.gz進行解壓並將打包文件釋放到當前目錄
    tar -zxvf local.tar.gz
    
    # 僅解壓指定的檔案local/script到當前工作目錄
    tar -zxvf local.tar.gz local/script
    
    # 將目錄/local進行打包並使用gzip進行壓縮,但排除以.log結尾的文件
    tar -zcvf local.tar.gz --exclude=*.log /local
    

top 動態查看進程

top命令可以實時的查看系統運行的整體情況,是一個綜合了多方信息監測系統性能和運行信息的實用工具。

  • 語法

    top [選項]
    
  • 選項

    • -d N N為数字,表示刷新秒數間隔
    • -b 以追加的方式显示結果
    • -n N N為数字,表示刷新次數
    • -p PIDLIST 只显示指定PID的進程,多個PID之間用,分隔
    • -u USER 只显示指定用戶的進程
    # 以1秒的時間間隔來動態查看進程
    top -d 1
    
    # 查看進程ID為 1 12 38 的進程信息
    top -d 1 -p 1,12,38
    

tail 查看文件末尾內容

tail 命令和head命令相反,用於查看文件末尾的內容,而且可以實時刷新

  • 語法

    tail [選項] 文件
    
  • 選項

    • -n N N為数字,表示末尾N行
    • -c N N為数字,表示行內的末尾的N個字節。UTF-8編碼中一個字母佔1字節,一個漢字佔3字節
    • -f 實時刷新显示文件內容
    # 實時查看文件/local/mylog.log末尾100行的內容
    tail -100f  /local/mylog.log
    

touch 修改文件的時間屬性或創建空文件

touch命令用於修改文件或者目錄的時間屬性,若文件不存在,則創建一個新的空文件。Linux下的三個時間屬性概念分別是atime(access time)讀取時間 、 mtime(modify time)修改時間、ctime(change time),注意ctime不是create time。實際工作中使用touch修改這些時間屬性的需求極少,相反大多數是用來創建一個或多個空文件。有點喧賓奪主的意思~

  • 語法

    touch [選項] 文件或目錄
    
  • 選項

    • -a 修改文件或目錄的讀取時間
    • -m 修改文件或目錄的修改時間
    • -t STAMP 指定時間戳,格式為[YYYY]MMDDhhmm[.ss]
    • -c 如果文件不存在,不要創建文件
    # 使用{}可一次性創建多個空文件,如 {1..10}  {a..z}  {1,3,5,7,9}
    # 創建一個空文件
    touch olympic.txt
    
    # 創建99空文件
    touch olympic{1..99}.txt
    
    # 修改文件的修改時間 mtime
    touch -cmt 200808080808.08 olympic.txt
    

useradd / groupadd 用戶和組管理

Linux系統是一個多用戶多任務的分時操作系統,任何一個要使用系統資源的用戶,都必須首先向系統管理員申請一個賬號,然後以這個賬號的身份進入系統。用戶的賬號一方面可以幫助系統管理員對使用系統的用戶進行跟蹤,並控制他們對系統資源的訪問;另一方面也可以幫助用戶組織文件,併為用戶提供安全性保護。每個用戶賬號都擁有一個唯一的用戶名和各自的密碼。用戶在登錄時鍵入正確的用戶名和密碼后,就能夠進入系統和自己的家目錄。

  • 添加用戶

    # 添加一個普通用戶,不指定組的話會自動創建一個同名組
    useradd jack 
    
    # 添加一個普通用戶,並指定現有的組(組必須先存在)
    useradd -g root jet
    
    # 添加一個系統用戶,並不讓其登錄 -r 代表系統用戶,系統用戶不會有家目錄
    useradd -r -s /sbin/nologin  rose 
    
  • 刪除用戶

    # 只刪除用戶
    userdel jack
    
    # 刪除用戶,並刪除該用戶的家目錄(包括目錄中的內容)
    # 家目錄外的用戶所屬文件會替換成用戶ID,當有新的用戶使用這個ID時,該文件自動歸屬新用戶
    userdel -r jack
    
  • 修改用戶

    # 修改用戶的初始用戶組,通過名稱修改
    usermod -g root jack
    
    # 修改用戶的初始用戶組,通過GID修改
    usermod -g 888 jack
    
    # 相當於passwd -l,鎖定用戶
    usermod -L jack
    
    # 相當於passwd -u,解除鎖定
    usermod -U jack 
    
    # 禁止用戶登錄
    usermod -s /sbin/nologin jack
    
    # 修改用戶ID
    usermod -u 888 jack
    
  • 查看用戶

    # 查看當前用戶
    id
    
    # 查看當前登錄的用戶
    w
    
    # 查看所有的用戶
    cat /etc/passwd
    cat /etc/passwd | cut -d ':' -f 1
    
  • 添加用戶組

    # 建立一個一般用戶組
    groupadd mygroup
    
    # 建立一個系統用戶組
    groupadd -r admingroup
    
  • 刪除用戶組

    # 刪除用戶組
    groupdel admingroup
    
  • 修改用戶組

    # 修改組ID
    groupmod -g 888 mygroup
    
    # 修改組名稱 CIA為新名稱
    groupmod -n CIA mygroup
    
  • 查看用戶組

    cat /etc/group
    

vi / vim 文本編輯器

vivim用法基本一致,它們的關係有些類似於Windows下notepad與notepad++的關係,不過vim有時默認沒有安裝,需要yum -y install vim手動安裝一下。因為vim相比vi,功能更強大,又有語法高亮等功能。所以個人還是習慣並推薦使用vim。下面介紹的vim的使用方法,通常在vi上同樣適用,網上介紹vim使用的方式基本上就是說在三種模式下使用總結,即命令模式、輸入模式、底線命令模式,介紹十分詳盡,簡直快把整個vim的幫助給弄下來了。我這裏介紹的常用操作為單位,不是很全,但日常使用應該足夠了。

  • 打開文件

    # 打開一個文件
    vim /tmp/yum.log
    
    # 按 ctrl+w 然後按 上下左右鍵 可在窗口之間切換
    # 打開多個文件,縱向窗口分割,左右一邊一個窗口
    vim -O /etc/hosts /etc/hosts.bak
    # 打開多個文件,橫向窗口分割,上下一遍一個窗口
    vim -o /etc/hosts /etc/hosts.bak
    
  • 編輯文本

    • 打開文件后,按i鍵可在光標處插入內容;按o鍵可在光標處的下一行插入內容。此時底部會显示-- INSERT --字樣,按Esc鍵可退出編輯模式
  • 快速定位

    • : set nu 显示行號, 按 : 然後輸入set nu敲回車
    • : set nonu 取消显示行號
    • : N N為数字,表示行號,按 : 然後輸入11,敲回車即可快速移動光標到第11行,輸入$則移動到最後一行
    • N% N為数字,表示百分比,比如按58然後按一下%,即可移動光標到文件58%的部分
    • H | M | L 按這三個鍵可快速移動光標到屏幕的頂部、中間、底部位置
    • ctrl+u 往上翻半頁
    • ctrl+d 往下翻半頁
    • ↑↓←→ 移動光標
    • Home/End 移動光標到行首或行末
    • PageUp/PageDown 翻頁
  • 快速編輯

    • N yy N為数字,複製光標所在行以下的N行,默認N為1,即當前行。如複製 20 行,就按20,然後按yy就複製了
    • N ddyy用法一樣,只不過它是剪切。所以它也能當刪除使用
    • p 在光標所在行的下一行粘貼剛複製或剪切的內容
    • uu鍵,撤銷剛才的操作
    • ctrl+r 反撤銷
    • v 進入視圖模式,可通過上下左右移動光標選擇一片文本,此時底部會显示-- VISUAL --字樣(按Esc鍵可退出視圖模式)然後按y複製或按d剪切,按p在光標處後面粘貼
    • Vv一樣,只不過是以行為單位
    • ctrl+vv一樣,只不過是以列為單位,類似於在notepad++中,按住Alt選文字
  • 查找

    • / KEYWORD/進入查找,在底部/的後面輸入想查找的內容,按回車搜索,然後按n往下繼續查找,按N往上查找
  • 替換

    • :%s#OLD#NEW#gic 個人習慣先按:%s###g,然後移動光標到OLD位置輸入要替換的字符串,在移動光標到NEW位置,輸入新字符串,敲回車進行文字替換,%表示全文,不加代表當前行,用10,20替換百分號則表示替換10到20行;後面的gicg表示全局替換不加只替換每行的第一個;i 表示忽略大小寫,c表示在替換前進行確認,需要哪個加哪個
  • 退出和保存

    • Esc 當你進入編輯模式、命令模式等其他模式時,都可按Esc鍵退出
    • :w 保存
    • :wq 保存並退出
    • q! 強制退出不保存

wc 統計字數行數

wc命令可以統計字節數、行數、單詞數

  • 語法

    wc [選項] 文件
    
  • 選項

    • -l 統計行數
    • -c 統計字節數
    • -m 統計字符數
    # 依次列出/etc/passwd中的 行數、字數、字符數
    wc /etc/passwd
    
    # 查看有多少個進程數
    ps -ef | wc -l
    

xargs 參數傳遞

xargs是給命令傳遞參數的一個過濾器,也是組合多個命令的一個工具,它可以將管道或標準輸入的數據轉換成命令行參數,也能夠從文件的輸出中讀取數據。它能夠捕獲一個命令的輸出,然後傳遞給另外一個命令,一般與管道在一起使用

# 找到修改日期在7天前的日誌,並將其刪除
find /local/server -name "*.log" -mtime +7 | xargs rm -rf

yum 紅帽系列包管理工具

yum,是Yellow dog Updater, Modified 的簡稱,是杜克大學為了提高RPM 軟件包安裝性而開發的一種軟件包管理器,適用於Redhat系列的系統。用python寫成,yum 的宗旨是自動化地升級,安裝/移除rpm 包,收集rpm 包的相關信息,檢查依賴性並自動提示用戶解決。yum 主要功能是更方便的添加/刪除/更新rpm 包,自動解決包的依賴性問題,便於管理大量系統的更新問題。yum 可以同時配置多個資源庫(Repository),簡潔的配置文件(/etc/yum.conf),自動解決增加或刪除rpm包時遇到的依賴性問題。

  • 語法

    yum [選項] 命令 [包名]
    
  • 選項

    • -y 對所有的確認都回答yes
  • 命令

    • install PACKAGE 安裝包,PACKAGE替換成要安裝的包名
    • update PACKAGE 更新包
    • remove PACKAGE 卸載包
    # 安裝 vim 
    yum -y install vim
    

zip / unzip 壓縮與解壓

zip 是個廣泛使用的壓縮程序,壓縮后的文件後綴名為.zip

# 將當前目錄下所有txt文本壓縮在一起
zip txt.zip *.txt

# 將目錄/local壓縮成local.zip文件
zip -r local.zip /local

# 將local.zip解壓縮到指定目錄,不加-d選項,則解壓到當前目錄
unzip local.zip -d ~/

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

新北清潔公司,居家、辦公、裝潢細清專業服務

※教你寫出一流的銷售文案?

分類
發燒車訊

【Spring註解驅動開發】關於BeanPostProcessor後置處理器,你了解多少?

寫在前面

有些小夥伴問我,學習Spring是不是不用學習到這麼細節的程度啊?感覺這些細節的部分在實際工作中使用不到啊,我到底需不需要學習到這麼細節的程度呢?我的答案是:有必要學習到這麼細節的程度,而且是有機會、有條件一定要學!吃透Spring的原理和源碼!往往拉開人與人之間差距的就是這些細節的部分,當前只要是使用Java技術棧開發的Web項目,幾乎都會使用Spring框架。而且目前各招聘網站上對於Java開發的要求幾乎清一色的都是熟悉或者精通Spring。所以,你,很有必要學習Spring的細節知識點。

項目工程源碼已經提交到GitHub:https://github.com/sunshinelyz/spring-annotation

BeanPostProcessor後置處理器概述

首先,我們來看下BeanPostProcessor的源碼,看下它到底是個什麼鬼,如下所示。

package org.springframework.beans.factory.config;
import org.springframework.beans.BeansException;
import org.springframework.lang.Nullable;
public interface BeanPostProcessor {
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

}

從源碼可以看出:BeanPostProcessor是一個接口,其中有兩個方法,postProcessBeforeInitialization和postProcessAfterInitialization兩個方法,這兩個方法分別是在spring容器中的bean初始化前後執行,所以spring容器中的每一個bean對象初始化前後,都會執行BeanPostProcessor接口的實現類的這兩個方法。

也就是說,postProcessBeforeInitialization方法會在bean實例化和屬性設置之後,自定義初始化方法之前被調用,而postProcessAfterInitialization方法會在自定義初始化方法之後被調用。當容器中存在多個BeanPostProcessor的實現類時,會按照它們在容器中註冊的順序執行。對於自定義BeanPostProcessor實現類,還可以讓其實現Ordered接口自定義排序。

因此我們可以在每個bean對象初始化前後,加上自己的邏輯。實現方式:自定義一個BeanPostProcessor接口的實現類MyBeanPostProcessor,然後在類MyBeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization方法裏面寫上自己的邏輯。

BeanPostProcessor後置處理器實例

我們創建一個MyBeanPostProcessor類,實現BeanPostProcessor接口,如下所示。

package io.mykit.spring.plugins.register.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

/**
 * @author binghe
 * @version 1.0.0
 * @description 測試BeanPostProcessor
 */
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("調用了postProcessBeforeInitialization方法,beanName = " + beanName + ", bean = " + bean);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("調用了postProcessAfterInitialization,beanName = " + beanName + ", bean = " + bean);
        return bean;
    }
}

接下來,我們運行BeanLifeCircleTest類的testBeanLifeCircle04()方法,輸出的結果信息如下所示。

調用了postProcessBeforeInitialization方法,beanName = animalConfig, bean = io.mykit.spring.plugins.register.config.AnimalConfig$$EnhancerBySpringCGLIB$$e8ab4f2e@56528192
調用了postProcessAfterInitialization,beanName = animalConfig, bean = io.mykit.spring.plugins.register.config.AnimalConfig$$EnhancerBySpringCGLIB$$e8ab4f2e@56528192
Cat類的構造方法...
調用了postProcessBeforeInitialization方法,beanName = cat, bean = io.mykit.spring.plugins.register.bean.Cat@1b1473ab
Cat的postConstruct()方法...
Cat的init()方法...
調用了postProcessAfterInitialization,beanName = cat, bean = io.mykit.spring.plugins.register.bean.Cat@1b1473ab
Cat的preDestroy()方法...
Cat的destroy()方法...

可以看到,postProcessBeforeInitialization方法會在bean實例化和屬性設置之後,自定義初始化方法之前被調用,而postProcessAfterInitialization方法會在自定義初始化方法之後被調用。

也可以讓實現Ordered接口自定義排序,如下所示。

package io.mykit.spring.plugins.register.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

/**
 * @author binghe
 * @version 1.0.0
 * @description 測試BeanPostProcessor
 */
@Component
public class MyBeanPostProcessor implements BeanPostProcessor, Ordered {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("調用了postProcessBeforeInitialization方法,beanName = " + beanName + ", bean = " + bean);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("調用了postProcessAfterInitialization,beanName = " + beanName + ", bean = " + bean);
        return bean;
    }

    @Override
    public int getOrder() {
        return 3;
    }
}

再次運行BeanLifeCircleTest類的testBeanLifeCircle04()方法,輸出的結果信息如下所示。

調用了postProcessBeforeInitialization方法,beanName = animalConfig, bean = io.mykit.spring.plugins.register.config.AnimalConfig$$EnhancerBySpringCGLIB$$b045438a@1ed1993a
調用了postProcessAfterInitialization,beanName = animalConfig, bean = io.mykit.spring.plugins.register.config.AnimalConfig$$EnhancerBySpringCGLIB$$b045438a@1ed1993a
Cat類的構造方法...
調用了postProcessBeforeInitialization方法,beanName = cat, bean = io.mykit.spring.plugins.register.bean.Cat@36c88a32
Cat的postConstruct()方法...
Cat的init()方法...
調用了postProcessAfterInitialization,beanName = cat, bean = io.mykit.spring.plugins.register.bean.Cat@36c88a32
Cat的preDestroy()方法...
Cat的destroy()方法...

BeanPostProcessor後置處理器作用

後置處理器用於bean對象初始化前後進行邏輯增強。spring提供了BeanPostProcessor的很多實現類,例如AutowiredAnnotationBeanPostProcessor用於@Autowired註解的實現,AnnotationAwareAspectJAutoProxyCreator用於SpringAOP的動態代理等等。

除此之外,我們還可以自定義BeanPostProcessor的實現類,在其中寫入需要的邏輯。下面以AnnotationAwareAspectJAutoProxyCreator為例,說明後置處理器是怎樣工作的。我們都知道springAOP的實現原理是動態代理,最終放入容器的是代理類的對象,而不是bean本身的對象,那麼spring是什麼時候做到這一步的?就是在AnnotationAwareAspectJAutoProxyCreator後置處理器的postProcessAfterInitialization方法,即bean對象初始化完成之後,後置處理器會判斷該bean是否註冊了切面,如果是,則生成代理對象注入容器。Spring中的關鍵代碼如下所示。

/**
  * Create a proxy with the configured interceptors if the bean is
  * identified as one to proxy by the subclass.
  * @see #getAdvicesAndAdvisorsForBean
  */
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (this.earlyProxyReferences.remove(cacheKey) != bean) {
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

好了,咱們今天就聊到這兒吧!別忘了給個在看和轉發,讓更多的人看到,一起學習一起進步!!

項目工程源碼已經提交到GitHub:https://github.com/sunshinelyz/spring-annotation

寫在最後

如果覺得文章對你有點幫助,請微信搜索並關注「 冰河技術 」微信公眾號,跟冰河學習Spring註解驅動開發。公眾號回復“spring註解”關鍵字,領取Spring註解驅動開發核心知識圖,讓Spring註解驅動開發不再迷茫。

部分參考:https://www.cnblogs.com/dubhlinn/p/10668156.html

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※想知道最厲害的網頁設計公司"嚨底家"!

※幫你省時又省力,新北清潔一流服務好口碑

※別再煩惱如何寫文案,掌握八大原則!

分類
發燒車訊

NFC芯片選型及基本電路框架

RFID作為一項專業度較高的技術,在一些公司,可能還會專門招聘專業的RFID工程師。本篇闡述的涉及到的只是基本選型設計、電路框架,關於RFID天線調試、低功耗檢卡調試等,後續再其他篇章會繼續更新!

 

NFC(Near Field Communication)芯片選型:

 

主要考量點:

芯片支持的協議、是否支持低功耗檢卡、是否能過金融認證、芯片價格

 

芯片支持協議:

  • ISO14443A/B、ISO15693、 ISO18092 和 ISO21481 等

  • ISO14443A 卡:Mifare 系列、 Ultralight 系列、 Plus 系列、 CPU 卡系列等。

  • ISO14443B 卡:身份證、 SR176、 SRI512 等。

  • ISO15693:NXP 的 ICODE 系列、 TI 的 Tag_it HF-I、 ST LRI 等。

  • ISO18092:包括讀卡模式、卡模式、點對點通信模式。

  • ISO21481:在 ISO18092 基礎上兼容 ISO15693 協議。

  • LPCD 功能:芯片低功耗檢測卡片功能。沒有卡片靠近時,芯片處於低功耗狀態, 僅需10uA 電流,就能完成卡片偵測, 當卡片靠近時,芯片偵測到卡片,喚醒單片機讀卡。

  • 金融認證:PBOC2.0/3.0 標準、 EMV 標準

 

電路架構:

 

NFC芯片外部電路通常由以下幾個部分組成:供電電路、通信接口電路、天線電路、振蕩電路;

供電電路:主要包括模擬電源AVDD、数字電源DVDD、發射器電源TVDD、引腳電源PVDD、測試引腳電源PVDD2;

a. 如果需要提高發射功率可提高TVDD的電壓,例如5V供電的TVDD形成的發射功率會比3V的要強;

b. 芯片的供電電流通常在幾十到幾百mA,主要的能量消耗在發射器的電路上。例如FM175xx的天線發射電流在100mA,RC663則可以達250mA,因此選擇供電芯片、電感器件時,需要注意留足余量;

c.讀卡芯片天線13.56MHz的正弦波信號會幹擾電源,為減少傳導干擾,可以在電源端加π型濾波器,但為減少電路設計冗餘度,一般情況下不添加。

 

通信接口:

通常都支持SPI/I2C/UART,一般通過外部引腳配置選擇,為方便升級,可做兼容設計;

 

天線設計:

天線電路主要由4部分組成:EMC濾波、匹配電路、天線、接收電路。以FM17550為例,如下:

濾波電路:

由L1、C1組成的低通濾波器用於濾除13.56MHz的衍生諧波,該濾波器截止頻率應設計在14MHz以上。L1電感不可靠近擺放,以免互相干擾(互感效應)。濾波電路元件匹配公式:f=1/(2π√LC)

 

匹配電路:

用於調節發射負載和諧振頻率。射頻電路功率受芯片內阻和外阻抗影響,當芯片內阻和外阻抗一致時,發射功率效率最高。C2是負載電容,天線感量越大,C2取值越小。C3是諧振電容,取值和天線電感量直接相關,使得諧振頻率在13.56MHz。

 

接收電路:

C4濾除直流信號,R2和R3組成分壓電路,使得RX接收端正弦波信號幅度在1.5-3V之間。

 

天線:

  • 由R1電阻(通常是1ohm或0ohm)和印製PCB組成。

  • 天線越大,讀卡距離越遠,當天線面積達到5cm x 5cm以後,再增大天線,讀卡距離沒有明顯提升。

  • 天線線寬建議選擇0.5mm – 1mm。天線大於5cm x 5cm不能多於3圈,小於3cm x 3cm不能小於4圈

  • 為減小EMC輻射干擾,需要將PCB走線轉角處畫成圓弧。

  • 天線區域內和天線邊緣禁止將信號、電源、地線畫成圈或者半圓,天線圈內不可有大面積金屬物體、金屬鍍膜,避免引起磁場渦流效應造成能力嚴重損耗。

  • 天線PCB繞線方式是相對的,不是同向。

  • 天線電路設計元件的精度應控制在2%以內,否則容易導致天線諧振頻點偏差,導致讀卡性能嚴重下降,產品一致性難以保證

天線大小和讀卡距離關係

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

新北清潔公司,居家、辦公、裝潢細清專業服務

※別再煩惱如何寫文案,掌握八大原則!

※教你寫出一流的銷售文案?

※超省錢租車方案

分類
發燒車訊

測試同學動手搭個簡易web開發項目

技術棧

node.js, vue.js, axios, python, django, orm, restful api, djangorestframework, mysql, nginx, jenkins.

環境配置

操作系統

Windows 7 旗艦版,Service Pack 1。

前端

Node.js

>node -v
v12.18.0
>npm -v
6.14.4

Vue.js

>vue -V(大寫)
@vue/cli 4.4.1

後端

Python

>python --version
Python 3.7.2

Django

>python -m django --version
3.0.7

數據庫

MySQL

>mysqladmin --version
mysqladmin  Ver 8.0.19 for Win64 on x86_64 (MySQL Community Server - GPL)

命令行登錄mysql,

>mysql -u root -p
Enter password: ******

查詢數據庫,

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| new_schema         |
| performance_schema |
| sakila             |
| sys                |
| world              |
+--------------------+
7 rows in set (0.00 sec)

代理

Nginx

在nginx安裝目錄執行start nginx,瀏覽器訪問http://localhost:80,

持續集成

Jenkins

安裝后,會自動打開http://localhost:8080/,

軟件安裝過程就不贅述了,聰明的你一定知道怎麼安。

項目搭建

本文的目的是走通整個項目的鏈路,於是會“弱化”掉系統功能的實現。

創建後端工程

執行django-admin startproject djangotest創建項目。

cd djangotest,執行python manage.py startapp myapp創建應用。

python manage.py runserver,啟動服務,訪問http://localhost:8000/,

創建RESTful API

安裝mysqlclient和djangorestframework,

pip --default-timeout=6000 install -i https://pypi.tuna.tsinghua.edu.cn/simple mysqlclient
pip --default-timeout=6000 install -i https://pypi.tuna.tsinghua.edu.cn/simple djangorestframework

在settings.py中,添加’rest_framework’和’myapp’,

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'rest_framework',

    'myapp',
]

同時修改數據庫配置,

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'HOST': '127.0.0.1',
        'PORT': 3306,
        'NAME': 'world',
        'USER': 'root',
        'PASSWORD': '123456'
    }
}

在myapp\models.py添加model,model叫做HellloDjango,有2個字段id和name,

from django.db import models

# Create your models here.


class HelloDjango(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(null=False, max_length=64, unique=True)

執行python manage.py makemigrations,提交,

>python manage.py makemigrations
Migrations for 'myapp':
  myapp\migrations\0001_initial.py
    - Create model HelloDjango

執行python manage.py migrate,創建,

>python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, myapp, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying myapp.0001_initial... OK
  Applying sessions.0001_initial... OK

看看數據庫,新增了auth_和django_開頭的表,以及model映射的表myapp_hellodjango,

mysql> show tables;
+----------------------------+
| Tables_in_world            |
+----------------------------+
| auth_group                 |
| auth_group_permissions     |
| auth_permission            |
| auth_user                  |
| auth_user_groups           |
| auth_user_user_permissions |
| city                       |
| country                    |
| countrylanguage            |
| django_admin_log           |
| django_content_type        |
| django_migrations          |
| django_session             |
| myapp_hellodjango          |
+----------------------------+
14 rows in set (0.00 sec)

插入2條測試數據,

mysql> insert into myapp_hellodjango(name) values('hello');
Query OK, 1 row affected (0.09 sec)

mysql> insert into myapp_hellodjango(name) values('django');
Query OK, 1 row affected (0.20 sec)

mysql> select * from myapp_hellodjango;
+----+--------+
| id | name   |
+----+--------+
|  2 | django |
|  1 | hello  |
+----+--------+
2 rows in set (0.00 sec)

照着官網的例子,在myapp目錄下新增urls.py,添加rest代碼,

from django.conf.urls import url, include
from rest_framework import routers, serializers, viewsets

from .models import HelloDjango


# Serializers define the API representation.
class HelloSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = HelloDjango
        fields = ['id', 'name']


# ViewSets define the view behavior.
class HelloViewSet(viewsets.ModelViewSet):
    queryset = HelloDjango.objects.all()
    serializer_class = HelloSerializer


# Routers provide an easy way of automatically determining the URL conf.
router = routers.DefaultRouter()
router.register(r'hello', HelloViewSet)

urlpatterns = [
    url(r'demo/', include(router.urls)),
]

在djangotest下的urls.py中添加路由,

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include('myapp.urls'))
]

通過這2個urls.py文件的指定,api接口的路徑為,/api/demo/hello。

執行python manage.py runserver啟動服務,使用postman來調用http://127.0.0.1:8000/api/demo/hello/。先發1個post請求,往數據庫新增1條數據,

再發1個get請求,會看到返回了3條數據,2條預先插入的數據,1條post請求新增的數據,

創建前端工程

在djangotest根目錄下,執行vue create vuetest,創建vue工程。

默認安裝,一路回車,啪啪啪。

開始創建,

Vue CLI v4.4.1
a  Creating project in D:\cicd\vuetest.
a  Initializing git repository...
aa Installing CLI plugins. This might take a while...

創建成功,

a  Successfully created project vuetest.
a  Get started with the following commands:

 $ cd vuetest
 $ npm run serve

執行cd vuetestnpm run serve,前端工程就啟動起來了,訪問http://localhost:8080/,Welcome to Your Vue.js App,

前端調後端接口

此時djangotest的目錄結構為,

├─djangotest
│  ├─djangotest
│  ├─myapp  # app
│  ├─vuetest  # 前端
│  ├─manage.py

修改vuetest\src\components\HelloWorld.vue,添加{{info}},用來展示後端api返回的數據,

<div class="hello">
  {{info}}
    <h1>{{ msg }}</h1>

同時在<script>中使用axios添加ajax請求,請求http://127.0.0.1:8000/api/demo/hello/,將response.data賦值給info,

<script>
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  data() {
    return {
        info: 123
    }
  },
  mounted () {
    this.$axios
      .get('http://127.0.0.1:8000/api/demo/hello/')
      .then(response => (this.info = response.data))
      .catch(function (error) { // 請求失敗處理
        console.log(error);
      });
  }
}
</script>

為了運行起來,需要安裝axios,

npm install --save axios

並在vuetest\src\main.js中引入,

import Vue from 'vue'
import App from './App.vue'
import axios from 'axios'

Vue.config.productionTip = false

Vue.prototype.$axios = axios;

new Vue({
  render: h => h(App)
}).$mount('#app')

分別啟動後端和前端服務,

python manage.py runserver
cd vuetest
npm run serve

嚯!ajax請求失敗了,F12可以看到報錯信息,

localhost/:1 Access to XMLHttpRequest at ‘http://127.0.0.1:8000/api/demo/hello/’ from origin ‘http://localhost:8080’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

django的端口是8000,vue的端口是8080,vue在請求django的時候,出現了跨域問題。瀏覽器有個同源策略,域名+端口+協議都相同才認為是同一來源。

通過配置django來解決,先安裝django-cors-headers,

pip install django-cors-headers

在settings.py中添加中間件和開關,

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'corsheaders.middleware.CorsMiddleware',  # 添加
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

CORS_ORIGIN_ALLOW_ALL = True  # 添加

此時vue就可以請求到django提供的接口了,http://localhost:8080/

前後端結合

vuetest目錄下創建vue.config.js,這是因為django只能識別static目錄下的靜態文件,這裏指定vue生成靜態文件時套一層static目錄,

module.exports = {
    assetsDir: 'static'
};

在vuetest目錄下執行npm run build,生成靜態文件到vuetest/dist文件夾。

修改urls.py,指定django的模板視圖,

from django.conf.urls import url
from django.contrib import admin
from django.urls import path, include
from django.views.generic import TemplateView

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include('myapp.urls')),
    url(r'^$', TemplateView.as_view(template_name="index.html")),
]

在settings.py中配置模板目錄為dist文件夾,

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': ['vuetest/dist'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

指定靜態文件目錄為vuetest/dist/static,

# Add for vuejs
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "vuetest/dist/static"),
]

瀏覽器訪問http://localhost:8000/,显示的不再是django的歡迎頁面,而是vue的頁面。

前後端結合完成。vue的8080可以停了。

Nginx轉發

nginx常用3個命令,啟動,重新加載,停止,

nginx start
nginx -s reload
nginx -s stop

修改\conf\nginx.conf,監聽端口改為8090,添加轉發proxy_pass http://localhost:8000;

   server {
        listen       8090;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   html;
            index  index.html index.htm;
            proxy_pass http://localhost:8000;
        }

執行nginx start,瀏覽器訪問http://localhost:8090/,也能正常訪問djangotest。

通過nginx將8090轉發到了8000。

持續集成

本來想弄個pipline的,無奈家裡這台破機器安裝失敗,windows也沒有linux對jenkins支持好,只能將就做個雞肋版本。

New Item,命名為vuetest,添加vue的build腳本,

d:
cd D:\cicd\djangotest\vuetest
npm run build

New Item,命名為djangotest,添加django的build腳本,

d:
cd D:\cicd\djangotest
python manage.py runserver

直接執行會報錯python不是可運行命令。添加python環境變量,在首頁左下角,

把路徑D:\Python37添加為環境變量path並保存,

建好的這2個job就可以用來編譯vue和啟動django了,

專註測試,堅持原創,只做精品。歡迎關注公眾號『東方er』
版權申明:本文為博主原創文章,轉載請保留原文鏈接及作者。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

新北清潔公司,居家、辦公、裝潢細清專業服務

※別再煩惱如何寫文案,掌握八大原則!

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※超省錢租車方案

※教你寫出一流的銷售文案?

分類
發燒車訊

Pytorch入門——手把手帶你配置雲服務器環境

本文始發於個人公眾號:TechFlow,原創不易,求個關注

今天這篇是Pytorch專題第一篇文章。

大家好,由於我最近自己在學習Pytorch框架的運用,並且也是為了響應許多讀者的需求,推出了這個Pytorch專題。由於這個專題是周末加更的,所以不能保證更新進度,我盡量和其他專題一樣,每周一更。

Pytorch簡介

Pytorch底層是Torch框架,Torch框架是一個科學計算框架,擁有一個與Numpy類似的張量操作庫。非常靈活,但是它的語言是Lua,比較小眾,因此沒有廣泛流行。

後來開發團隊在Torch的基礎上包裝了一層Python的Api,使得我們可以通過Python來進行調用。它是由Facebook的人工智能小組開發維護的,目前在業內也非常流行,尤其是學術界,幾乎清一色的Pytorch。它擁有兩個最大的優點,一個是動態網絡,像是TensorFlow等框架定義出來的神經網絡是靜態的,一旦寫死不能輕易改變。但是Pytorch我們可以零延遲地改變任何神經網絡。第二個有點是具有強大的GPU加速計算的工具,Pytorch的GPU加速非常好用。

另外Pytorch的語法更加簡潔規範,更加Pythonic,學習曲線也更平穩一些。寫出來的代碼更加容易理解,更適合初學者。

當然由於誕生的時間還短,並且在工業界的普及度還不如TensorFlow,所以它也有一些短板,比如一些底層的文檔不夠完善,一些功能欠缺等等。在我個人的學習和使用當中,我的體驗非常好,因此如果你沒有學過深度學習的框架的話,推薦使用它作為你的第一門框架。

雲服務器

既然是深度學習的框架,那麼最好是能夠擁有GPU環境。但是對於我們大多數人而言,GPU環境並不是一個容易的事情。比如我是Mac黨,本身的機器就沒有N卡,外接也不方便。當然沒有GPU用CPU硬肝也是可以的,不過發熱很嚴重,對電腦也有損傷。所以,最好的辦法就是租借網上的GPU雲服務器或者是雲服務。

推薦一下滴滴雲服務器,我個人使用下來體驗還不錯,最便宜的只要兩塊多一個小時,應該比網吧上網便宜。最近在搞巨大活動,包年雲GPU只要2200,簡直是白菜價中的白菜價。注意這個優惠只能第一筆下單的時候享受。如果感興趣的話可以訪問鏈接:https://i.didiyun.com/2cvmFVGpCjz

查看原文

因為我是特邀用戶,所以我拿到了內部優惠的大師碼,如果要購買其他GPU雲服務器的話,可以在付款的時候輸入我的大師碼2323,可以再享受9折優惠。

當然你也可以購買裝好環境的Notebook,或者是按照時常購買。Notebook好處是預裝了各種環境,上手可用,但是缺點是不支持定製化,一些操作不太方便。畢竟有了雲服務器可以自己搭建Notebook,但是Notebook並不支持服務器的功能。

如果你想要使用其他雲服務器平台,可以查看我之前的文章

想要學深度學習但是沒有GPU?我幫你找了一些不錯的平台

環境配置

為了防止一些小白租借了機器不會用,接下來提供一下配置環境的詳細教程(基於滴滴雲)。如果你用的別家的服務器,由於環境不一定完全相同,所以可能並不一定適用,只能當做參考。

總之我們整個流程是:安裝Python3,安裝jupyter,配置jupyter遠程訪問,安裝Pytorch

這些是明面上的流程,如果機器環境不健全,還會有一些隱藏流程。比如說普通的Linux環境需要配置apt-get,還需要下載git,wget等常用工具。如果沒有cuda驅動的話,還需要自己安裝cuda配置。如果其中的步驟出現了問題,還需要分析問題的原因解決問題。所以說配置環境說起來簡單,但是實際操作的時候問題並不少。

安裝Python3

yum install python36

安裝 jupyter notebook

sudo pip3 install ipython jupyter notebook lab

設置jupyter的密碼

jupyter notebook password

生成jupyter notebook的配置,這個配置默認不存在,需要我們通過這個命令來生成。

jupyter notebook --generate-config

運行之後,會返回配置文件所在的路徑:

我們用vim打開,修改其中的幾行:

c.NotebookApp.ip='0.0.0.0'
c.NotebookApp.open_browser = False
c.NotebookApp.port =8888 # 可以自己指定

我們需要將本地的端口和遠程進行綁定,這樣我們就可以在本地打開遠程的jupyter了。這一行代碼當中我們將本地的8899綁定了遠程的8888端口。這裏的8888端口就是上面配置當中的遠程的jupyter端口。

ssh dc2-user@116.85.10.225 -L 127.0.0.1:8899:127.0.0.1:8888

如果你喜歡的話,還可以安裝一下jupyter lab

sudo pip3 install jupyterlab

使用方法和notebook類似,在遠程執行命令開啟jupyter

jupyter lab --allow-root

啟動沒有問題的話,我們在本地訪問:http://localhost:8899就可以打開Jupyter,輸入密碼之後就可以使用了。

當我們用完了雲服務器之後,要記得刪除機器。但由於平台機器數量有限,根據當前平台的設置,關機之後依然會為用戶保留資源,但是前提是需要付費。如果你是按時租的服務器顯然不能接受自己沒在使用還需要付費。針對這個問題,我們可以通過快照來解決。我們在關機之前先創建快照

然後刪除雲服務器,下次重新創建服務器的時候選擇從快照創建。這樣下次創建的機器還可以保留當前的配置和數據,而且也不需要扣費了。如果你嫌麻煩的話,還可以加我的微信聯繫我,我幫你找到工作人員加入關機免扣費的白名單

我們用pip安裝一下Pytorch和一些其他需要用到的包。安裝好了,之後,我們通過torch.cuda.is_avaiable()查看一下cuda的情況,如果輸出是True,那說明已經安裝好了。

tensor

Pytorch當中很重要的一個概念就是tensor,它直譯過來是張量,TensorFlow當中的tensor也是這個意思。我們可以認為tensor是一個高維的數組。當它是0維的時候就是一個數,一個標量。當它是一維的時候就是一個向量,二維的時候是一個矩陣,多維的時候是高維的數組。它和Numpy當中的數組類似,不過Tensor可以使用GPU進行加速。

我們通過torch當中的接口來初始化tensor,和Numpy當中的數組類似,它支持好幾種初始化的方式。

empty函數創建一個指定大小的未初始化的tensor,當中的元素內容是不可保證的。

rand創建一個隨機初始化的數組:

ones和zeros創建全是0或者全是1的數組:

我們可以傳入類型指定元素的類型

我們也可以通過現成的數組創建tensor:

這些創建函數都有對應的like方法,可以傳入一個已有的tensor,創建出一個和它一樣大小的新的tensor來。

這裏只是列舉了常用的幾種,官方的api當中還有其他的幾種創建tensor的方式:

除此之外,tensor還支持從numpy的數組當中創建,我們可以利用from_numpy函數來實現:

同理,我們也可以通過numpy函數,從一個tensor得到numpy的數組:

還可以通過tolist方法將tensor轉化成Python的數組:

函數 功能
Tensor(*sizes) 基礎構造函數
tensor(data,) 類似np.array的構造函數
ones(*sizes) 全1Tensor
zeros(*sizes) 全0Tensor
eye(*sizes) 對角線為1,其他為0
arange(s,e,step) 從s到e,步長為step
linspace(s,e,steps) 從s到e,均勻切分成steps份
rand/randn(*sizes) 均勻/標準分佈
normal(mean,std)/uniform(from,to) 正態分佈/均勻分佈
randperm(m) 隨機排列

我們在創建tensor的時候不僅可以指定它們的類型,還可以指定它們存放的設備。比如是CPU還是GPU。當然前期我們暫時用不到這點,只需要記得即可。

總結

這是Pytorch的第一篇文章,我們簡單了解了一下這個框架,以及它當中tensor這個數據結構。簡單來說,我們可以用常用的Numpy去類比它。基本上Numpy當中有的功能它都有,它還有一些自己特性Numpy沒有的api。但不管怎麼說,萬變不離其宗,tensor的用處就是為了方便我們處理數據的

關於Pytorch中tensor的用法還有很多,實在是沒有辦法在一篇文章當中窮盡,所以這裏只是簡單介紹,具體的用法將會放在下一篇文章當中,讓我們下周再見吧。

如果喜歡本文,可以的話,請點個關注,給我一點鼓勵,也方便獲取更多文章。

本文使用 mdnice 排版

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※教你寫出一流的銷售文案?

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※回頭車貨運收費標準

※別再煩惱如何寫文案,掌握八大原則!

※超省錢租車方案