實際跑過之後,覺得這款軟體真的很不錯。在Coding的時候幫了很多忙。
Bash One-Liners Explained, Part I: Working with files Note
在網路上看到這篇,做一下自己的筆記
替代,新增指定內容的字串到文件
1 | $ echo "Line 1" > file |
新增字串到檔案最尾端
1 | $ echo "Line 2" >> file |
清空檔案內容
將檔案內容全部清空,檔案大小歸零,以下兩種作法效果是一樣的。不過第二種比較容易看懂。
1 | $ > file |
讀取一行資料
可以用以下方式讀取出來
1 | $ read -r line < file |
這個方式會將頭尾的空白去掉,且保留字串中的反斜線(-r)。
如果要設定IFS的話,可以順便切割赤串。
1 | $ cat "1, 2, 3" > file |
Read前面的IFS只影響當前的read指令,執行完之後恢復原狀。
原作中所說的
1 | $ echo " Emptry End" > file |
保留空白一點效果都沒有,只好寫成這個樣子
1 | $ SAVEIFS=$IFS |
另外也可以用這種寫法
1 | $ line=${head -1 file} |
也可以這樣寫
1 | $ IFS= line=${head -1 file} |
這邊的IFS就正常了,應該是Bash的Bug吧@@。
讀取文件的每一行
1 | $ while IFS= read -r line; do |
另一種寫法,利用pipe來做
1 | $ cat file | while IFS= read -r line; do |
隨機讀取檔案的任合一行
同樣的,達成這樣功能也是有很多作法,例如使用Process substitution建立一個匿名pipi。
1 | $ read -r random_line < <(shuf file) |
上面的shuf是用來此亂檔案中美一行的排列順序,而取打亂檔案的第一行。不然可以用sort -R
代替。
同樣的也可以使用Pipe來達成工作。
1 | $ random_line=$(sort -R abcd | head -1) |
讀取前三個字串
假設目前檔案內容是aaa bbb ccc ddd eee
。我們可以用
1 | $ read -r var1 var2 var3 throwaway < file |
如果不在var3後面加個變數的話,var3的內容救變成ccc ddd eee
了。
如果你根本不關心throwaway內容的話,可以寫成
1 | $ read -r var1 var2 var3 _ < file |
如果檔案內容是aaa bbb
的話,var3的內容就是空的。
讀取一個文件檔有幾行,幾個單字,字元數目
同樣的,以上面aaa bbb ccc ddd eee
為範例。基本上就是上面的技巧,加上wc的輸出結果。wc的用法google一下即可。
1 | $ read -r lines words chars _ < <(wc abcd) |
直接從字串中讀取資料
假設我們現在有個字串$info叫做`20 packets in 10 seconds”,如何取出packets跟time。
使用awk的作法會是
1 | $ packets=$(echo $info | awk '{ print $1 }') |
透過Here strings跟read指令可以寫的更輕鬆
1 | $ read packets _ _ time _ <<< $info |
獲得檔案的大小
一樣是wc的用法,只不過現在只需要char count。
1 | $ size=$(wc -c < file) |
從文件路徑獲得文件名稱根目錄資訊
看起來很襖,不過實際上使用有其侷限。假設我們現在的路徑名稱是/path/to/file.ext
,接著我們可以透過parameter expansion來擷取。
1 | $ dirname=${path%/*} |
不過檔案路徑改成非path開頭的,filename的定義也要跟著修改。
快速拷貝/搬移文件
透過Brace expansion,可以方便我們做這件事。
1 | $ cp /path/to/file{, _copy} // cp path/to/file path/to/file_copy |
How to Remove All Unused Linux Kernel Headers, Images and Modules
每次更新的時候,都會塞了一堆重複的Image/Headers/Modules在系統裡面。如何移除他們
Ubuntu
請參考這邊作法
1 | $ dpkg -l 'linux-*' | sed '/^ii/!d;/'"$(uname -r | sed "s/\(.*\)-\([^0-9]\+\)/\1/")"'/d;s/^[^ ]* [^ ]* \([^ ]*\).*/\1/;/[0-9]/!d' | xargs sudo apt-get -y purge |
CentOS
我是參考這篇作法
1 | ## Install yum utils ## |
Linux的指令真的非我強項啊。看的眼花蓮亂,有時間在研究。
Misc C++11 Feature Part 2
前一篇還是漏掉一些東西,因此才有這篇的存在。
Delegating constructors
在其他程式語言行之有年的玩意,終於加入C++11了。
1 | class Num { |
Raw String literals
也是在其他程式語言行之有年的觀念
1 | #include <iostream> |
執行結果是
1 | First line. |
在Raw String
中的特殊符號都不會被處理。
static_assert
在C++98的時代,就已經有Boost.StaticAssert和Loki library可以在編譯期找出可能的錯誤。這項特色終於被加入語言之中。
1 | static_assert( constant-expression, string-literal ); |
而沒有這項特色的C語言,就只能使用Stackoverflow的方式來做。
nullptr
原本NULL的定意識
1 | #ifndef NULL |
當如果有兩個同名函數
1 | void foo(int) {} |
不過實際使用上,NULL比nullptr更顯眼,畢竟目前對nullptr做Syntax highlight的editor還不多。
Misc C++11 Feature
儲存了一堆文件,消化一下。
Default template arguments for function templates
以下這個程式碼,在C++98是不可行,但是C++11可以的。
1 | template <typename T = int> void Foo(T t = T()) |
根據Stackoverflow的說法,可以寫類似這樣的Code>
1 | template <typename Iterator, typename Comp = std::less<Iterator>> |
不過當Function Template在Argument deduction時,可能會有以下的問題。
1 | template <typename B, typename T = int> |
同樣的在Function Template overload的時候,也是地雷區。
1 | template <typename T = int> void Foo(T t = T()) {} |
C++真是細節有夠多的程式語言。
Explicit conversion operators
在C++98的時候,explicit
能做的就只有這樣。
1 | class Test1 { |
而對這樣的處理無能為力。
1 | class Test1 { |
t2被偷偷轉換成Test1類型而無法輕易發現,在C++11之後,增加了這樣的能力。
1 | class Test2 { |
不過bool算是例外。
1 | class Test3 { |
Initializer lists and Uniform initialization syntax
在C語言可以這樣寫沒問題
1 | int a[] = {1, 2, 3}; |
不過在C++98,用std::vector
的時候,就只能寫成這樣。
1 | std::vector<int> a; |
支援Initializer lists
之後,終於可以寫出比較美觀的程式碼
1 | std::vector<int> a = {1, 2, 3}; |
你也在自己的城市中使用Initializer lists,如下:
1 | template <typename T> |
既然有了Initializer lists之後,C++11更進一步將Initialization簡化,使用同樣的語法來做初始化。
Case 1:
1 | struct C |
Case 2
1 | int* a = new int[3] { 1, 2, 0 }; //C++11 only |
Case 3
1 | struct X { |
Case 4:
1 | struct C |
更進一步,將Initializer list和 Uniform initialization雙見合併。
1 | map<string, string> singers ={ {"Lady Gaga", "+1 (212) 555-7890"}, |
這樣的程式碼易讀許多。
Software optimization resources (C++/ASM)
Agner Fog最近更新了他的Software optimization resources。
之前在Corel的時候也有參考過這邊的文件。不過離開那邊之後就沒碰過Assembly了。
不過Optimizing software in C++: An optimization guide for Windows, Linux and Mac platforms這篇文件可以看看。
這年頭自己寫Assembly的人越來越少,除了是大師之外,沒有把握比Compiler做的更好。
List of free programming books
有人整理過,完全合法,可自由取得的城市設計書籍。
- List of free programming books
- Coder Heya
- Become a Programmer, Motherfucker
另外 - pineapple.io 提供了很多教學文件
- hacker shelf 提供了不錯的書單
Why cannot use linux as varaible name?
在StackOverflow看到的。
這段程式,在GCC和Clang會失敗,而在VC正常運作。
1 | int main() |
用gcc -E
下去看的結果如下
1 | int main() |
這是由於在未標準化的年代,像是unix,linux等字都會採到地雷。
不過可以用 gcc -std=c89
強讓他走標準規範編譯。
可以看到
1 | $ cpp --std=c89 -dM < /dev/null | grep linux |
在gnu89裡面GCC自己加了linux的定義下去了。注意這邊的cpp
是The C Preprocessor,跟C++無關。
用-dM
來印出所有被Preprocessor定義的值。
既然知道Preprocessor定一些什麼值之後,就可以順利避開陷阱了。
Common concept on programming languages
東西閱看越多姿後,才發覺自己的無知。 寫起來當筆記。
First-class citizen
Wiki上有其定義。另一個名稱叫First-class object,其特性有
- 可以被存入變數或其他結構
- 可以被作為參數傳遞給其他函數
- 可以被作為函數的返回值
- 可以在執行期創造,而無需完全在設計期全部寫出
- 即使沒有被繫結至某一名稱,也可以存在
其中最具討論性的是函數算不算First-class citizen,C/C++不支援在Runtime創造函數,所以不把函數視為First-class citizen。
Higher-order unction
[Wiki](http://en.wikipedia.org/wiki/Higher-order_function)上同樣有定義。一個Higher-order unction至少滿足以下條件之一。
- 接受一個或多個函數作為輸入
Closure
Wiki同樣有其定義。
用在一個函式與一組「私有」變數之間建立關聯關聯。在給定函式被多次呼叫的過程中,這些私有變數能夠保持其永續性。變數的作用域僅限於包含它們的函式,因此無法從其它程式代碼部分進行存取。不過,變數的生存期是可以很長,在一次函式呼叫期間所建立所生成的值在下次函式呼叫時仍然存在。正因為這一特點,閉包可以用來完成訊息隱藏,並進而應用於需要狀態表達的某些編程典範中。
用這種方式來使用閉包時,閉包不再具有參照透明性,因此也不再是純函式。
Tailing Recursion and its variation
Tailing Recursion是大部分Function Language的基本配備,在沒有迴圈的情況下,Recursive是唯一的方案。
而Tailing Recursion是Tail Call的一種特例。只是最後呼叫的函數是自己。
在不討綠用公式解跟迴圈解的情況下,要從1加到1000000000我們會這麼寫。
1 | long long sum(int n) |
這段程式在Visual C++會掛,而在GCC跟Clang可以正常運作。 (Visual C++的判別還真有點弱)。
不過我想說的是後面這個,Tailing Recursion Optimization
。
跟上面很類似,不過會多帶一個參數,代表初始狀態。
上面的範例可以重新寫成
1 | long long int sum(int n, long long int v) |
這種寫法比上面好的點,在於當我們要做Recursive呼叫的時候,必須保留呼叫時每一層的狀態,存在Stack裡,當你遞迴深度過深時,超過OS給予的極限,就會造成Stackoverflow。而用下面這種寫法的話,則不需要保留遞迴中的堆疊。只需要修改當前堆疊的值,然後既需呼叫函式即可。
還有如果把之後要做的事情當做參數傳進來,就變成Continuation-passing style了。
把程式碼改寫成這樣
1 | void sum(int n, long long int v, function<void (long long)> contWith) |
結果所有編譯器全掛了,同樣邏輯的程式碼用Haskell重寫一次
1 | sum' n total cont |
整個計算資源被耗盡了,難道1000000000真的玩太大了。