2020年7月20日 星期一

Linux - Shell Scripts (3) (pipe : grep)

管線命令 ( Pipe )

    管線命令是用 "|" 去連接,只要前一資料能變成 standard input。管線命令僅會處理 standard output,而不會處理 standard error output。下面用時下最夯的 MBTI 作的假資料。
index    name    MBTI
1        JunYe   ISTJ
2        JunYe   ISTP
3        JunYe   ESTP
4        JunYe   ESTJ
5        Mario   ISFJ
6        Mario   ISFP
7        Mario   ESFP
8        Mario   ESFJ
9        Joel    INFJ
10       Joel    INFP
11       Joel    ENFP
12       Joel    ENFJ
13       Joel    INTJ
14       Joel    INTP
15       Joel    ENTP
16       John    ENTJ
17       John    ESFP
18       Peter   ESFJ
19       Peter   INFJ
20       Peter   INFP
21       Peter   ENFP
22       Eva     ESTJ

基本管線命令 grep

    grep會在每一行找尋配對的字串,然後列出來。
$ bash pipeData.sh | grep "JunYe"
1        JunYe   ISTJ
2        JunYe   ISTP
3        JunYe   ESTP
4        JunYe   ESTJ
    加 -v 找每一行沒配對的字串,然後列出來。
$ bash pipeData.sh | grep -v "JunYe"
index    name    MBTI
5        Mario   ISFJ
6        Mario   ISFP
7        Mario   ESFP
8        Mario   ESFJ
9        Joel    INFJ
10       Joel    INFP
11       Joel    ENFP
12       Joel    ENFJ
13       Joel    INTJ
14       Joel    INTP
15       Joel    ENTP
16       John    ENTJ
17       John    ESFP
18       Peter   ESFJ
19       Peter   INFJ
20       Peter   INFP
21       Peter   ENFP
22       Eva     ESTJ
上一篇 :

2020年7月16日 星期四

Linux - Shell Scripts (2)

sh vs bash

    我有時候用 sh 會讓 shell script 執行不過,通常會報 Bad substitution 之類的錯誤。其實是因為我用 ubuntu,ubuntu 的 sh 其實是指到 dash 而非 bash。dash 在這不作多介紹, 把它想像成輕量型的 bash,所以支援的功能有限,所以有機會報錯。
ubuntu: cd /bin/
ubuntu: /bin$ ls -l
lrwxrwxrwx 1 root root       4  4月  9 16:36 sh -> dash

shell 字串操作

    #!/bin/bash
    # Shell 字串操作
    # 執行 bash string.sh

        file=/dir1/dir2/dir3/my.file.txt

        # 字串刪減
        # '#' 專刪右邊
        echo ${file#*/}   # 從左邊開始批配,刪掉 / 自身和其左邊的字串:dir1/dir2/dir3/my.file.txt
        echo ${file##*/}  # 從右邊開始批配,刪掉 / 自身和其左邊的字串:my.file.txt
        echo ${file#*.}   # 從左邊開始批配,刪掉 . 自身和其左邊的字串:file.txt
        echo ${file##*.}  # 從右邊開始批配,刪掉 . 自身和其左邊的字串:txt
        # '%' 專刪右邊
        echo ${file%/*}   # 從右邊開始批配,刪掉 / 自身和其右邊的字串:/dir1/dir2/dir3
        echo ${file%%/*}  # 從左邊開始批配,刪掉 / 自身和其右邊的字串:
        echo ${file%.*}   # 從右邊開始批配,刪掉 . 自身和其右邊的字串:/dir1/dir2/dir3/my.file
        echo ${file%%.*}  # 從左邊開始批配,刪掉 . 自身和其右邊的字串:/dir1/dir2/dir3/my

        # 取子字串
        echo ${file:0:5}  # 從 index 為 0 之字元,往後取 5 個:/dir1
        echo ${file:5:5}  # 從 index 為 5 之字元,往後取 5 個:/dir2

        # 字串取代
        echo ${file/dir/path}  # 將第一個 dir 取代成 path:/path1/dir2/dir3/my.file.txt
        echo ${file//dir/path} # 將全部的 dir 取代成 path:/path1/path2/path3/my.file.txt

    exit 0

shell 陣列操作

    # Array 操作

        declare -a ARRAY      # 宣告 array 可以省略
        ARRAY=(first second third)
        echo ${ARRAY[0]}      # first
        echo ${ARRAY[1]}      # second
        echo ${ARRAY[2]}      # third
        echo ${ARRAY[*]}      # first second third
        echo ${ARRAY[*]:1:2}  # second third
        echo ${ARRAY[@]:1:2}  # second third
        
    exit 0
上一篇 :
下一篇 :

2020年7月14日 星期二

Linux - Shell Scripts (1)

sh v.s source

    如果直接用 sh 執行 script,基本上就是開一個子程序去執行 script。所以父程序要獲得子程序的結果,通常都是靠著 export 解決 scope 的不同。若是使用 source 去執行 script,則是直接用本身程序去執行,所以本身與腳本享有共同 scope。更多請參考 : 鳥哥私房菜

基本的 variable & operator

    基本上 shell 的語法網路上有很多相關資料,這邊我想紀錄的是那些對於菜鳥不怎麼直觀的 variable & operator。而且其實我認為 shell 的精華就是在這些 variable & operator。
  • variable
        #!/bin/sh
            # 執行 : sh variable.sh a b c 
            echo $0         # script 本身
            echo $1 $2 $3   # 執行 script 時, 後面跟著的 arguments
            echo $#         # arguments 之總數
            echo $*         # 全部 arguments, 這個例子就是 a b c 
            echo $@         # 全部 arguments, 這個例子就是 a b c ($* $@ 應該有所不同, 不過我試不出來...)
            echo $?         # 上一個程式最後回傳值 (exit 0)
            echo $$         # 此 shell 的 pid
            echo $!         # 此 shell 最後執行的 background process 的 pid
        exit 0
  • operator
        #!/bin/sh
        # 執行 : sh operator.sh 20 10 
            
            # 此格式為固定的, ``, operator 前後要有空格
            # expr 不會檢查 $1 跟 $2, 所以沒有的話會出錯
            # 即使加了 "" 也會被判定 null, 等於 non-integer 也是錯 
            val=`expr $1 + $2`    # 相加
            val=`expr $1 - $2`    # 相減
            val=`expr $1 \* $2`   # 相乘 (*須加反斜線)
            val=`expr $1 / $2`    # 相除
            val=`expr $1 % $2`    # 取餘數
    
            # ==, !=, >, <, >=, <=
            if [ $1 = $2 ]; then
                val="equal"
            fi
    
            if [ $1 != $2 ]; then
                val="non-equal"
            fi
    
            if [ $1 -eq $2 ]; then
                val="equal"
            fi
    
            if [ $1 -ne $2 ]; then
                val="non-equal"
            fi
    
            if [ $1 -gt $2 ]; then
                val="greater than"
            fi
    
            if [ $1 -lt $2 ]; then
                val="less than"
            fi
    
            if [ $1 -ge $2 ]; then
                val="greater or equal"
            fi
    
            if [ $1 -le $2 ]; then
                val="less or equal"
            fi
        exit 0
  • 更多 operator
        #!/bin/sh
            # 執行 : sh operator2.sh 字串1 字串2 ...
            # 參數判斷時, 最好加上 "", 否則有高機率失效, 並出現 unary operator expected 等錯誤.
            if [ -z "$1" ]; then
                echo "there's no argument"
            fi
    
            if [ ! -z "$1" ]; then
                echo "there's at least one argument (!-z)"
            fi
    
            if [ -n "$1" ]; then
                echo "there's at least one argument (-n)"
            fi
    
            if [ "$1" ]; then
                echo "#1 argument is exist"
            fi
    
            # boolean operator -a = and, -o = or
            if [ "$1" -a "$2" ]; then
                echo "#1 and #2 arguments are both exist"
            fi
    
            if [ "$1" -o "$2" ]; then
                echo "there's at least one argument"
            fi
        exit 0
參考資料 :
下一篇 :

2020年7月11日 星期六

英文歌詞翻譯 Rudimental - These Days feat. Jess Glynne, Macklemore & Dan Caplen


I know you moved onto someone new
我知道你已經開始尋找新對象
Hope life is beautiful
希望你過得很好
You were the light for me to find my truth
你曾經是我追尋自我的燈塔
I just wanna say, thank you
現在我只想說 謝謝你

Leaving to find my soul
為了找尋真正的自我
Told her I had to go
告訴她我必須走了
And I know it ain't pretty
我知道這一點都不美好
When our hearts get broke
當彼此的心破碎
Too young to feel this old
還太年輕去體驗這殘酷的離別
Watching us both turn cold
看著兩個人漸行漸遠
Oh, I know it ain't pretty
我知道這一點都不美好
When two hearts get broke
當彼此的心破碎
Yeah, I know it ain't pretty
我知道這一點都不美好
When two hearts get broke
當彼此的心破碎

I hope someday
我希望有天
We'll sit down together
我們仍能坐在同一塊地方
And laugh with each other
一起暢談歡笑
About these days, these days
回憶曾經的時光
All our troubles
所有當初的不和
We'll lay to rest
我們都能釋懷放下
And we'll wish we could come back to these days, these days
讓我們甜蜜的回憶這段時光
These days, these days
那些時光
These days, these days
曾經的時光

Three years of ups and downs
經歷了三年的起起伏伏
Nothing to show for it now
現在卻一句話也說不出來
And I know it ain't pretty when the fire burns out
我知道這一點都不美好 當感情消逝殆盡
Calling me when I'm drunk, remind me of what I've done
在我沉浸酒精時數落我 一筆一筆算著我曾經錯誤
And I know it ain't pretty when you're trying to move on, yeah
我知道這一點都不美好 當你試著離開
I hope someday
我希望有天
We'll sit down together
我們仍能坐在同一塊地方
And laugh with each other
一起暢談歡笑
About these days, these days
回憶曾經的時光
All our troubles
所有當初的不和
We'll lay to rest
我們都能釋懷放下
And we'll wish we could come back to these days, these days
讓我們笑著回憶這段時光
Oh I know, I know
噢 我知道 我知道
Oh I know, I know
噢 我知道 我知道
Oh I know, I know
噢 我知道 我知道
These days, these days
這些時光 這些美好的時光
Oh I know, I know
噢 我知道 我知道
Oh I know, I know
噢 我知道 我知道
Oh I know, I know
噢 我知道 我知道
These days, these days
這些時光 這些美好的時光

Cigarettes in the ash tray
香菸靜靜地躺在菸灰缸裡
Reminiscing on those past days
回憶著那些日子
I thought you'd end up with my last name
我曾經以為你最終會是我的老婆
But that changed
但一切都變了
And I travelled around the world
我的足跡踏遍全世界
Think where you living at now?
卻想著你住在何方
I heard you moved to Oxford
我聽說你搬到 Oxford
Got an apartment and settled down
在一個公寓安頓下來
And every once in a while
每過段時間
I start texting
我就想著與你聯繫
Write a paragraph
但我寫了一個段落後
But then I delete the message
便停筆不寫了
Think 'bout you like a past time
像過往一樣地想起妳
I could cry you a river
我便淚流滿面
Get you baptised or
足以讓你沉浸在裡的那種
I wasn't ready to act right
我還沒準備好與你相遇
Used to always think I'd get you back, right
過去總想著挽回妳
They say that things fall apart (yeah)
他們說一切早已分崩離析
We were gonna move to Brooklyn
我們原本要一起搬到 Brooklyn
You were gonna study Art (oh no, oh)
妳原本要學藝術
Love is just a tool
原來愛情是一個工具
To remind us who we are
提醒著我們真正的自己
And that we are not alone
但現在我們已不孤單
When we're walking in the dark
當我們走在夜空下
備註 :
單身 30 年的我在聽到這首歌,腦中總會顯現那段不曾存在的戀情。這首歌送給有妄想症的單身狗。

讀書心得 - C++ Primer (5th Edition) - Chapter 2 (3) - Type Aliases



Type Aliases

    創造資料型態的同義詞,通常是用 typedef 來去實現。
    typedef double wages;   // wages is a synonym for double
    typedef wages base, *p; // base is a synonym for double, p for double*

auto

    寫程式常會有想要一個 variable 去儲存 expression 的運算結果,但要事先知道 expression 的最終資料型態非常困難。所以有 auto 這個特別的資料型態,讓編譯器決定其資料型態,但相對的 variable 一定要 initialize。
    auto item = val1 + val2; // item initialized to the result of val1 + val2
    因為 auto 一次只能當一個資料型態,所以在宣告時如果是用 ", " 分開的複數宣告,資料型態要一致。
    auto i = 0, *p = &i;      // ok: i is int and p is a pointer to int
    auto sz = 0, pi = 3.14;   // error: inconsistent types for sz and pi
    auto 與 const 的互動,基本上 auto 會忽視 top level const ( 物件本身為 const )。
    const int ci = i, &cr = ci;
    auto b = ci;       // b is an int (top-level const in ci is dropped)
    auto c = cr;       // c is an int (cr is an alias for ci whose const is top-level)
    auto d = &i;       // d is an int*(& of an int object is int*)
    auto e = &ci;      // e is const int*(& of a const object is low-level const)
    若想要個 top level auto const,你只能在 auto 前加 const 修飾詞。
    const auto f = ci; // deduced type of ci is int; f has type const int

decltype()

    不同於 auto,decltype() 可以不用去計算 expression,只讓編譯器去分析其資料型態。下面程式碼,編譯器不會呼叫 f(),而是去檢查 f() 的 return 資料型態去給予 sum。
    decltype(f()) sum = x;     // sum has whatever type f returns
    decltype() 也可以與 top level const 互動。
    const int ci = 0, &cj = ci;
    decltype(ci) x = 0;     // x has type const int
    decltype(cj) y = x;     // y has type const int& and is bound to x
    decltype(cj) z;         // error: z is a reference and must be initialized
上一篇 :

2020年7月9日 星期四

讀書心得 - C++ Primer (5th Edition) - Chapter 2 (2) - Const



修飾詞 : Const

    如果我們想要一個不可被改變的參數,這時就會需要這個修飾詞 ( Qualifier ) const。
    const int bufSize = 512;  // input buffer size
    bufSize = 1024;           // error: attempt to write to const object

Const + Reference

    Const + Reference 代表 Reference to const,等於你不能使用這個 Reference 去改變物件。沒有 const 修飾詞 ( plain object ) 的 reference 不可以 bind 有 const 修飾詞的物件,但反之有 const 修飾詞的 reference 可以 bind 無 const 修飾詞的物件。
    int i = 1;
    const int &r = i;  // we can bind a const int& to a plain int object
    i = i + 1;         // "r" will be 2 too.
    r = r + 1;         // error: assignment of read-only reference "r"
    int &j = r;        // error: binding ‘const int’ to reference of type ‘int&’ discards qualifiers

Const + Pointer ( const type * var )

    跟 Reference 一樣 Pointer to const,等於你不能使用這個 Pointer 去改變物件。沒有 const 修飾詞 ( plain object ) 的 Pointer 不可以 bind 有 const 修飾詞的物件,但反之有 const 修飾詞的 Pointer 可以 bind 無 const 修飾詞的物件。
    const double pi = 3.14;     // pi is const; its value may not be changed
    double *ptr = &pi;          // error: ptr is a plain pointer
    const double *cptr = &pi;   // ok: cptr may point to a double that is const
    *cptr = 42;                 // error: cannot assign to *cptr

Const + Pointer ( type * const var )

    但 Pointer 跟 Reference 不一樣,本身也是物件,所以可以 const pointer。const pointer 則必須被 initialized。但因為是 const pointer 而不是 const 指向物件,所以可以用 const pointer 去改變物件。
    int numb = 0;
    int * const cptr1 = &numb;  // cptr1 will always point to numb
    int * const cptr2;          // error: uninitialized const 'cptr2'
    *cptr1 = 5;                 // numb will be 5 too.

top-level/lower-level const

    像 pointer 的 const 就有兩種,所以稱 const pointer object 這種本身為 top-level,稱 point to const 這種為 lower-level。
    int i = 0;
    int *const p1 = &i;       // we can't change the value of p1; const is top-level
    const int ci = 42;        // we cannot change ci; const is top-level
    const int *p2 = &ci;      // we can change p2; const is low-level
    const int *const p3 = p2; // right-most const is top-level, left-most is not
    const int &r = ci;        // const in reference types is always low-level

constexpr ( constant expression )

    constant expression 等於 expression 不能被改變,也就等於這個 expression 必須在編譯時期就可以被計算出來。以下為 constant expression 的例子。
    const int max_files = 20;        // max_files is a constant expression
    const int limit = max_files + 1; // limit is a constant expression
    int staff_size = 27;             // staff_size is not a constant expression
    const int sz = get_size();       // sz is not a constant expression
    int i; 
    const int size1 = i; 
    constexpr int size2 = i;      // error: the value of ‘i’ is not usable in a constant expression
    constexpr int mf = 20;        // 20 is a constant expression
    constexpr int limit = mf + 1; // mf + 1 is a constant expression
    constexpr int sz = size();    // ok only if size is a constexpr function
    constexpr 跟 pointer 的作用
    const int *p = nullptr;       // p is a pointer to a const int
    constexpr int *q = nullptr;   // q is a const pointer to int
相關文章 :
上一篇 :
下一篇 :

2020年7月3日 星期五

讀書心得 - C++ Primer (5th Edition) - Chapter 2 (1) - Primitive Types



C++ 原生內建的資料型態 ( Primitive Types )

    C++ 定義了一些算術用的資料型態 ( Arithmetic Types ) 和一個特殊的資料型態 void。Arithmetic Types : Integer, Character, Boolean, Floating Point, Double Floating Point, Wide Character。

    下面為一些資料型態轉換 :
    bool b = 42;            // b is true
    int i = b;              // i has value 1
    i = 3.14;               // i has value 3
    double pi = i;          // pi has value 3.0
    unsigned char c = -1;   // assuming 8-bit chars, c has value 255
    signed char c2 = 256;   // assuming 8-bit chars, the value of c2 is undefined

Initialization

    各種初始 :
    int units_sold1 = 0;
    int units_sold2 = {0};
    int units_sold3{0};
    int units_sold4(0);
    {} 跟 () 的不同 :
    long double ld = 3.1415926536;
    int a{ld}, b = {ld};    // error: narrowing conversion required
    int c(ld), d = ld;      // ok: but value will be truncated

Declaration 跟 Definition

    為了支援多個檔案的編譯,cpp 區分了 Declaration 跟 Definition。Declaration 代表著跟整個程式宣告一個帶有資料型態的名子,任何檔案都可以去作存取。Definition 則是創造一個物件實體去對應那個帶有資料型態的名子。
    如果想要只宣告名子(代表實際物件會被在其他檔案給實現),則會在宣告時加上 extern,有了 extern 就代表你不能下 Definition。
    extern int i;              // declares but does not define i
    int j;                     // declares and defines j
    extern double pi = 3.1416; // error: ‘pi’ has both ‘extern’ and initializer

Compound Types - References

    Reference 等於創造額外的一個名子給一個物件。所以下面第 refVal2, refVal4 會 error,因為你不能給不存在的物件 ( 或 rvalue ) 取名。References must be initialized.
    int ival = 1024;
    int &refVal = ival;     // refVal refers to (is another name for) ival
    int &refVal2;           // error: a reference must be initialized
    int &refVal3 = refVal;  // ok: refVal3 is bound to the object to which refVal is bound, i.e., to ival
    int &refVal4 = 10;      // error: initializer must be an object

Compound Types - Pointers

    Pointer為一個 "指向" 物件。類似 References 但卻是一個物件,所以可以不用被 initialized,也可以用來複製、分配。下面的 & 是作為 operator,用來取物件的實際位置,與上面提到用來宣告資料型態的的 & 有著不同的意義。
    double dval;
    double *pd = &dval; // ok: initializer is the address of a double
    double *pd2 = pd;   // ok: initializer is a pointer to double
    int *pi = pd;       // error: types of pi and pd differ
    pi = &dval;         // error: assigning the address of a double to a pointer to int
    下面的 * 作為 operator,放在 pointer 前面等於取其指向的該物件
    *p = 0;             // * yields the object; we assign a new value to ival through p
    std::cout << *p;    // prints 0

更多 References & Pointers 範例

    double dval;
    double *pd = &dval;  // ok: initializer is the address of a double
    double *pd2 = pd;    // ok: initializer is a pointer to double
    int *pi = pd;        // error: types of pi and pd differ
    pi = &dval;          // error: assigning the address of a double to a pointer to int

    int i = 42;
    int &r = i;          // & follows a type and is part of a declaration; r is a reference
    int *p;              // * follows a type and is part of a declaration; p is a pointer
    p = &i;              // & is used in an expression as the address-of operator
    *p = i;              // * is used in an expression as the dereference operator
    int &r2 = *p;        // & is part of the declaration; * is the dereference operator
相關文章 :
上一篇 :
下一篇 :

Popular Posts