Jex’s Note

使用 Swftools 將 Pdf 轉成圖片

libfreetype6

apt-get install libfreetype6

libgif-dev

apt-get install libgif-dev

libjpeg-dev

apt-get install libjpeg-dev
apt-get upgrade --show-upgraded

zlib1g-dev、freetype

sudo apt-get install zlib1g-dev
sudo apt-get install freetype*

安裝swftools

需先安裝

sudo apt-get install make
sudo apt-get install g++

取得最新版並安裝:

cd /tmp
wget http://www.swftools.org/swftools-2013-04-09-1007.tar.gz
tar -xvf swftools-2013-04-09-1007.tar.gz
cd swftools-2013-04-09-1007
./configure
sudo make
sudo make install

Jodconverter 將word等..轉成pdf

libreoffice

sudo apt-get install libreoffice

fonts dir : /usr/lib/libreoffice/share/fonts/truetype

install font:

example : 文泉驛微米黑 http://wenq.org/wqy2/index.cgi?MicroHei

cd /tmp
wget http://downloads.sourceforge.net/project/wqy/wqy-microhei/0.2.0-beta/wqy-microhei-0.2.0-beta.tar.gz
tar zxvf wqy-microhei-0.2.0-beta.tar.gz
sudo mv wqy-microhei /usr/lib/libreoffice/share/fonts/truetype
rm -rf wqy-microhei*

install jodconverter:

wget https://jodconverter.googlecode.com/files/jodconverter-core-3.0-beta-4-dist.zip
unzip jodconverter-core-3.0-beta-4-dist.zip
mv jodconverter-core-3.0-beta-4 /home/jex/

usege :

java -jar /home/jex/jodconverter-core-3.0-beta-4/lib/jodconverter-core-3.0-beta-4.jar Fonts.docx fonts.pdf

LVM

切割LVM硬碟

1) 檢查有無 PV 在系統上,然後將 /dev/hda6~/dev/hda9 建立成為 PV 格式

sudo pvscan

(會顯示lvm那個partition資料)

2) 建立vg

sudo vgcreate jex /dev/sda5

3) 檢查有無vg

sudo vgscan

4) 顯示vg內容(主要是取得Free PE(example:214564))

sudo vgdisplay

5) 建立lv

sudo lvcreate -l 214564 -n jex-lv jex-vg
Logical volume "jex-lv" created

6) 顯示lv內容(主要是取得LV Path(lv的全名, mkfs要用的))

sudo lvdisplay

7) 檔案系統格式化

sudo mkfs.xfs /dev/jex-vg/jex-lv

8) mount

sudo mount -t xfs /dev/jex-vg/jex-lv /test -o pquota

PHP Switch(0)的問題

當switch帶0進去後會發生一些問題,先來看以下的範例:

function result($num)
{
    switch ($num)
    {
        case $num < 60 :
            echo '<60';
            break;
        case $num > 60 :
            echo '>60';
            break;
        default:
            echo "I don't know!";
            break;
    }
}

echo result(0);    // 結果:>60
echo result(1);    // 結果:<60

為什麼!?

答案就在 官方手冊這一頁Loose comparisons with == 這邊,意思是說當帶0進去時它的判斷會是 0 == (0<60),結果就不會是你預期的,因為0在模糊比對裡也就是代表著false

那什麼情況要用if else什麼情況用switch?

當你要比對的是一個值而不是一個判斷句則使用switch就沒有問題 ex :

case 3 :
    echo '這是3';
    break;

如果要比對的是一個判斷句,代入>0的數值不會出問題,但當代入0時就會出問題,這不是php的bug,只能算是使用上的認知錯誤,因為我們以為它的判斷為0 > 60,但實際上是0 == (0>60),所以比對判斷句就使用if else吧!

    case $num > 60 :
        echo '大於60';
    break;

ref: 夯哥

Linux - Locale

指令

查詢目前的語系設定:

$ locale
locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_MESSAGES to default locale: No such file or directory
locale: Cannot set LC_ALL to default locale: No such file or directory
LANG=zh_TW.UTF-8
LANGUAGE=
LC_CTYPE="zh_TW.UTF-8"
(...略...)
LC_MEASUREMENT="zh_TW.UTF-8"
LC_IDENTIFICATION="zh_TW.UTF-8"
LC_ALL=

查詢已安裝的語系:

$ locale -a
locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_MESSAGES to default locale: No such file or directory
locale: Cannot set LC_COLLATE to default locale: No such file or directory
C
C.UTF-8
POSIX

Error: No such file or directory

locale: Cannot set LC_CTYPE to default locale: No such file or directory

解決方法:

sudo locale-gen --lang zh_TW.UTF-8
Generating locales...
  zh_TW.UTF-8... done
  Generation complete.

再執行locale指令就會正常了

參考來源:

http://120.105.184.250/peiyuli/network-2/shell-scripts.htm

Error: cannot change locale

-bash: warning: setlocale: LC_CTYPE: cannot change locale (UTF-8)
-bash: warning: setlocale: LC_CTYPE: cannot change locale (UTF-8)

解決方法, 2選1

在 .bashrc 加上

export LANG=en_US.utf-8
export LC_ALL=en_US.utf-8

或在 /etc/environment 加上

LANG=en_US.utf-8
LC_ALL=en_US.utf-8

Shell Script 基本語法

接收傳入參數

建立test.sh內容:

#!/bin/bash
echo $0
echo $1
echo $2

執行你的shell檔案,並將要傳入的參數加在後面

$ sh test.sh hello 11 22
test.sh         # 檔名
hello           # 第一個參數
11              # 第二個參數

讀寫檔案內容

建立test.sh內容:

cat > qq.php << EOF
this is line 1
this is line 1
EOF

執行後就會產生qq.php檔案了,檔案內容為EOF框起來的內容

寫檔換行 :

echo -e "line1\nline2" | tee -a /tmp/q.txt

append到檔案最後面

tee -a /tmp/t.txt << EOF
line 1
line 2
EOF

讀取檔案,將每行放入陣列

file=1.txt

seq=1
while read line
do
    lines[$seq]=$line
    ((seq++))
done < $file

for ((i=1;i<=${#lines[@]};i++))
do
    echo ${lines[$i]}
done

使用sh執行會有錯誤,但bash執行沒問題

或 :

array_1=($(cat /tmp/t.txt))
echo ${array_1[0]}

使用sh執行會有錯誤,但bash執行沒問題

set

錯誤直接停止, 在最上面加上:

set -e

錯誤不停止,繼續執行

set +e

其他:

  • set -- : 正常看到-後面是option,現在不再是option 而是一個命令參數。如-1 -2 …
  • set -a : 從這邊以後變數自動變成環境變數。
  • set -f : 不要解釋檔名的特殊字元例如wildcard *不再解釋為所有的意思了。
  • set -x : debug shell scripts
  • set -o ignoreeof : 一定要用exit離開shell,本來按Ctrl-D(eof)也可以
  • set -o noclobber : 關掉I/O導向不準overwrite檔案
  • set -o notify : shell結束時報告background job的status
  • set -o noglob : 關掉wildcard字元解釋 如 * ? [ ]
  • set +o : 把-o的反向操作
  • set - : 關掉-v -x -三種選項
  • set -- : 或者 set - 常常用在shell scripts裡面。 set -o 是很常用的例如set -o vi設定shell的操作方式用vi方法, 取回上個命令就是按ESC再按k囉。

ref:

if else

t.sh :

#!/bin/bash

num=$1

if [ "${num}" == "XD" ]; then
    echo "= XD"
elif [ "${num}" != "QD" ]; then
    echo "!= QD"
else
    echo "Nothing"
fi

執行 :

$ bash t.sh XD
= XD
$ bash t.sh something
!= QD
$ bash t.sh QD
Nothing

AND / OR :

[ "${confirm}" == "y" ] && [ "${confirm}" == "Y" ]
[ "${confirm}" == "y" ] || [ "${confirm}" == "Y" ]

switch

case $1 in
    "aa")
        echo "aa"
        ;;
    "cc")
        echo "cc"
        ;;
    "dd")
        echo "dd"
        ;;
    *)
        echo
        echo "  ***\$1 doesn't match!"
        echo
        exit
        ;;
esac

迴圈

for

for var in con1 con2 con3 ...
do
    // do something
done

or

for ((i=0; i<6; i++)); do
  echo $i
  if [ ${i} == 3 ]; then
        continue
        // break
  fi
  echo "done"
done

while

i=1
while [ $i -le 5 ]      // i < 5
do
    ((i++))
    echo $i
done

until

until [ condition ]
do
    程式段落
done

陣列

lines=('line1' 'line2' 'line3')

${#array[@]} 為array的總數 ${array[0]} 索引從0開始, -1為最後一個值

判斷

檔案是否存在

if test -e /etc/network/if-pre-up.d/firewall; then
    echo "/etc/network/if-pre-up.d/firewall exists.."
fi

or

if [ -f /tmp/${filename}.tar.gz ]; then
    echo "exist"
fi

判斷沒有目錄直接離開:

if [ ! -d "/var/www/$dir" ]; then
    echo "/var/www/$dir doesn't exist."
    exit
fi

判斷變數是否存在

if [ -z $1 ]; then
        # 不存在
else
        # 存在
fi

判斷只能輸入數字

echo "$1" | grep -o "^[0-9]*$"
if [ $? -eq 0 ] ;then
    echo "match found"
else
    echo "match not found"
fi

AND 條件

if (( $hour >= 0 )) && (( $hour <= 9 )); then
    # do something
else
    # do something
fi

亂數 10~19 中其中一個數字

shuf -i 10-19 -n 1

執行command結果給變數

random_num=$(shuf -i 10-19 -n 1)

or

count=$(grep "2017-07-07 $hour_str:$min_str" /var/log/php/ci/log-2017-07-07.php | wc -l)

How to run mysql commands through shell script?

mysql -u root test_database << EOF
SELECT * FROM test
EOF

有設定免密碼所以不用加 -p

在shell script執行 發生Bad substitution錯誤

可能發生的原因 ex: shell script 可能使用 ${str:3} (取得str變數第三個字元以後的字串)

因為sh不支援,所以執行時改用bash執行就可以解決了

bash test.sh

執行 ssh 後要怎麼離開

以下是沒有用的:

ssh qq.com
exit

要改成:

ssh qq.com <<ENDHERE
exit
ENDHERE

shell script 回覆 yes

當我要reload supervisor這個套件,但是會有新的一行yes/no,所以要使用這種方法才可以讓shell script幫我填入yes

sudo supervisorctl <<EOF
reload
y | command-that-asks-for-input
EOF

or

yes | sudo sensors-detect
sudo sensors

shell script 下 sudo echo 發生 permission denied

sudo echo "123" >> /etc/fstab

>> 是bash執行,不具root權限,以tee 代替>>

改成:

echo "123" | sudo tee -a /etc/fstab

-a, –append : append to the given FILEs, do not overwrite

match string

只比對jex, 其餘不要

bash :

#!/bin/bash

jex=$(echo $1 | grep -o "jex[0-9]*")
echo ${jex}

-o, –only-matching

取得指定字串長度

str='123456'
echo ${str:3:2}        # 結果為45

read讓使用者輸入變數

sudo fdisk -l
read -p "Please input XFS partition: " xfs_partition
echo $xfs_partition

執行漸進式選項

EX: fdisk partition

(echo o; echo n; echo p; echo 1; echo ; echo; echo w) | sudo fdisk

判斷 command 是否執行成功

some_command
if [ $? -eq 0 ]; then
    echo OK
else
    echo FAIL
fi

The return value is stored in $?. 0 indicates success, others indicates error.

比對檔案是否有符合字串

grep "127.0.1.1" /tmp/hosts > /dev/null 2>&1
if [ $? -eq 0 ]; then
    echo 'match'
fi

function

的第一種寫法,並返回值

function test ()
{
    return 255
}

test
echo $?

結果 : 255 return 範圍是 0~255,超過的話 : 256 為 0 257 為 1 使用 $? 取得 return 的值

第二種寫法,傳值並返回

test2 () {
 echo $1$2
}

string=$(test2 "Hello" " World!")
echo $string

結果 : Hello World! function 並不像 php 一樣順序可以放在執行後,shell script 的 function 必須放在執行前

背景執行不顯示 output

host www.google.com > /dev/null 2>&1

將 command 結果存入陣列

function test_dev_list()
{
    echo "/dev/sda5"
    echo "/dev/sda6"
    echo "/dev/sda7"
    echo "/dev/sda10"
    echo "/dev/sda11"
    echo "/dev/sda14"
}

dev_array=(`echo $(test_dev_list) | cut  -d " " --output-delimiter=" " -f 1-`)
for ((i=0; i<${#dev_array[@]}; i++)); do
    echo $i : ${dev_array[$i]}
done

結果:

0 : /dev/sda5
1 : /dev/sda6
2 : /dev/sda7
3 : /dev/sda10
4 : /dev/sda11
5 : /dev/sda14

減法

a=5
b=3
c=$(($a-$b))
echo $c

結果 : 2

輸出顏色文字及控制背景顏色

printf "\33[0;35;44m"
echo " Menu of available command:"
printf "\33[0m"
printf "\E[0;31;40m"
echo " Menu of available command:"
printf "\E[0m"
printf "\e[0;36;43m"
echo " Menu of available command:"
printf "\e[0m"

\33 = \E = \eprintf 來輸出,而不是一般的 echo

註 :

  • Syntx : \E[樣式;文字顏色;背景顏色m
  • 輸出文字 : \E[0m

樣式:

  • 0 一般樣式
  • 1 粗體
  • 4 加底線
  • 5 灰底
  • 7 文字及背景顏色對調

文字顏色:

30 黑色    90 暗灰
31 紅色    91 亮紅
32 綠色    92 亮綠
33 黃色    93 亮黃
34 藍色    94 亮藍
35 紫色    95 亮紫
36 青藍綠  96 亮青藍綠
37 亮灰    97 白

背景顏色:

40 黑色    100 暗灰
41 紅色    101 亮紅
42 綠色    102 亮綠
43 黃色    103 亮黃
44 藍色    104 亮藍
45 紫色    105 亮紫
46 青藍綠  106 亮青藍綠
47 亮灰    107 白

ref : 參考顏色 http://mark528.pixnet.net/blog/post/7267334-shell-script%3A-%E6%8E%A7%E5%88%B6%E6%96%87%E5%AD%97%E9%A1%8F%E8%89%B2

printf + read

printf "Choose Monkey, are you sure (y/n) ? "
read xfs_choice_confirm

read 後面不需接 -p

補充 if 參數

  • n1 -lt n2 : n1 小於 n2 (less than)
  • -a file : True if file exists.
  • -b file : True if file exists and is a block special file.
  • -c file : True if file exists and is a character special file.
  • -d file : True if file exists and is a directory.
  • -e file : True if file exists.
  • -f file : True if file exists and is a regular file.
  • -g file : True if file exists and is set-group-id.
  • -h file : True if file exists and is a symbolic link.
  • -k file : True if file exists and its ‘‘sticky’’ bit is set.
  • -p file : True if file exists and is a named pipe (FIFO).
  • -r file : True if file exists and is readable.
  • -s file : True if file exists and has a size greater than zero.
  • -t fd : True if file descriptor fd is open and refers to a terminal.
  • -u file : True if file exists and its set-user-id bit is set.
  • -w file : True if file exists and is writable.
  • -x file : True if file exists and is executable.
  • -O file : True if file exists and is owned by the effective user id.
  • -G file : True if file exists and is owned by the effective group id.
  • -L file : True if file exists and is a symbolic link.
  • -S file : True if file exists and is a socket.
  • -N file : True if file exists and has been modified since it was last read.
  • file1 -nt file2 : True if file1 is newer (according to modification date) than file2, or if file1 exists and file2 does not.
  • file1 -ot file2 : True if file1 is older than file2, or if file2 exists and file1 does not.
  • file1 -ef file2 : True if file1 and file2 refer to the same device and inode numbers.

  • [ -b $file ] True if file exists and is block special.

  • [ -c $file ] True if file exists and is character special.
  • [ -d $file ] True if file exists and is a directory.
  • [ -e $file ] True if file exists.
  • [ -f $file ] True if file exists and is a regular file.
  • [ -g $file ] True if file exists and is set-group-id.
  • [ -k $file ] True if file has its “sticky” bit set.
  • [ -L $file ] True if file exists and is a symbolic link.
  • [ -p $file ] True if file exists and is a named pipe.
  • [ -r $file ] True if file exists and is readable.
  • [ -s $file ] True if file exists and has a size greater than zero.
  • [ -S $file ] True if file exists and is a socket.
  • [ -t $fd ] True if fd is opened on a terminal.
  • [ -u $file ] True if file exists and its set-user-id bit is set.
  • [ -w $file ] True if file exists and is writable.
  • [ -x $file ] True if file exists and is executable.
  • [ -O $file ] True if file exists and is owned by the effective user id.
  • [ -G $file ] True if file exists and is owned by the effective group id.

ref: http://www.troubleshooters.com/linux/quickhacks.htm#ShellscriptFileTests

確認是否要執行以下指令

confirm() {
    echo "Press ENTER to continue, or ^C to cancel.";
    read -e ignored
}
confirm

判斷 Ubuntu 版本

LTS="Ubuntu 10.04"
ISSUE=`cat /etc/issue`
if [[ $ISSUE != Ubuntu* ]]; then
    echo "This script is intended for use on Ubuntu, but this system appears
    echo "to be something else. Your results may vary."
    echo
elif [[ `expr match "$ISSUE" "$LTS"` -eq ${#LTS} ]]; then
    echo "what"
fi

是否擁有 sudo 權限

echo "Testing sudo..."
sudo true
if [ $? -ne 0 ]
then
    echo "ERROR: You must be able to sudo to run this script.";
    exit 1;
fi;

動態偵測輸入變數

for TOKEN in $*
do
   echo $TOKEN
done

判斷第幾個參數

if [ $# -lt 1 ]; then

line 10: php: command not found

在使用 shell 的 bash 指令裡使用 php 指令記得要用絕對路徑

可使用 which php 查路徑在哪

指定 USER 執行命令

/usr/bin/sudo -H -u $USER bash -c "php -l qq.php"

每秒執行一次

while true
do
    /bin/sleep 1s
done

Add cron by command line

先印出已存在的 crontab, 然候新增你要的存進去

(crontab -l; echo "0 * * * * your_command") |uniq - | crontab -

Other way

echo "0   0  *  *  * your_command" | sudo tee -a /var/spool/cron/crontabs/jex

Remove cron by command line

先印出已存在的 crontab, 再用 sed 去刪除

crontab -l | sed "/pattern/d" | crontab -

other way

sudo sed -i "/pattern/.*$/d" /var/spool/cron/crontabs/jex

2>&1

2>&1 表示將stderr導向輸出stdout

0: stdin 1: stdout 2: stderr

out.file 2>&1 : out.file是將command的輸出重定向到out.file文件,即輸出內容不打印到屏幕上,而是輸出到out.file文件中。2>&1是將標准出錯重定向到標準輸出,這裡的標準輸出已經重定向到了out.file文件,即將標准出錯也輸出到out.file文件中。 ref: http://www.cnblogs.com/caolisong/archive/2007/04/25/726896.html

截取目錄名

jex@106-185-47-26:~/dockerfile/33-fsx$ echo ${PWD#*-}
fsx

當使用echo 增加資料發生Permission denied

$ sudo echo 'xxx' >> /etc/projects
-bash: /etc/projects: Permission denied

解決方法:

sudo echo 'xxx' | sudo tee -a /etc/projects

multi commands

alias lock='gnome-screensaver; gnome-screensaver-command --lock'

or

lock() {
    gnome-screensaver
    gnome-screensaver-command --lock
}

MySQL Index 解說

為什麼要建立索引:

適當的設定index可以有效的降低資料庫查詢的時間, 但這是以空間爭取時間的做法, 所以建立索引必須先考量到常被查詢的欄位

如果查詢時判斷多個欄位, 建立多組欄位的索引也要考量優先順序, 才能有效降低索引所佔用的資料庫空間

索引的規則:

假設有一組索引是uid+gid+ctime

  • where條件不分先後順序, 假設ctime先再來是uid及gid, 也是符合的
  • 這組索引的重要順序也是依你設定的順序為主, 假設你的索引是uid+ctime, 那麼這組索引只有uid對你有效
  • 如果條件是gid+ctime這組索引是沒有效用的, 因為這組索引是由uid先開始排
  • 換句話說條件為uid+uname的話, 這組索引至少也可以幫你減少搜尋uid的時間n 但uname沒在索引上, 所以mysql還是得一行一行找

使用 EXPLAIN 來檢查執行命令後索引的使用狀況

EXPLAIN SELECT *
FROM  `user_log`
WHERE uid =2
AND gid =2
AND ctime >0

結果:(只列出重要的)

key : uid+gid+ctime  (使用到的索引)
raw : 4              (查詢筆數)

參考來源:夯哥

排序(ORDER BY)

mysql 排序是按照該欄位的編碼, 例如 utf8_unicode_ci 就是按照 UTF8(unicode) 的順序去排 數 > 英 > 日 > 中 > 韓

也可以用 COLLATE 指定排序的編碼

utf8(unicode) table

不會使用到 index 的狀況 (innodb)

如果 where 多個已經有建 index 的欄位, 不會使用到 index

user_id = 'A01' or user_id = 'A02'
IN('A01','A02')

單個才會使用到 index

user_id = 'A01'
IN('A01')

欄位優化

IP 用 int unsigned 存

> echo ip2long('10.0.115.80');
> 167801680

修改大 TABLE (Innno DB)

新增欄位

目前測試的量沒有很多, 但可以參考看看

環境: AWS RDS Aurora MySQL 5.6.10a (db.t2.small)

MySQL 5.6 以前不支援 ALTER table without locking table, 如果是 5.6 又是 InnoDB 的話,可以放心 alter,TABLE 不會被 lock

130 萬筆資料庫的檔案大約需要 67s,cpu 會吃 35%,一直 insert 也很順, 不會影響到服務

不建議建立另一個沒 data 的 TABLE, 先 ALTER 後再 copy 舊 TABLE 到新的, 因為 cpu 會吃到 80% 以上, 操作也略為複雜

修改欄位屬性 (ALTER TABLE)

這個動作會 lock table, INSERT / UPDATE / SELECT 都會, 它會先執行 copy to tmp table, 所以會整個會卡死

300 萬筆就足夠 lock 30 分以上

加欄位跟index

不會 lock table

  • 新開一個 m3.medium RDS (與 prod 等級相同) 來測試新增一個 index (只 index 一個欄位), 將近 580 萬筆的 table, 需 10 min 40.88 sec CPU 會上升 20%, 但在 prod 實際執行時只需 2 min 33.05 sec CPU 一樣上升 20% (目前還不清楚為什麼 prod 需要的時間短很多)

新增 index

這個動作不會 lock table

對大 table 做 CRUD 的效能參考

860 萬的 table

SELECT

SELECT count(*) FROM `call_cv_history` WHERE event_at <= '2018-03-19 23:59:59';
  • event_at 範圍是1天的話是 1 row in set (0.50 sec)
  • event_at 範圍是10天的話是 1 row in set (5.14 sec)

event_at 有設 idnex, type 為 datetime

DELETE

DELETE FROM `call_cv_history` WHERE event_at <= '2018-03-20 23:59:59' LIMIT 50000;
  • LIMIT 是 10,000 的話是 Query OK, 10000 rows affected (0.91 sec)
  • LIMIT 是 50,000 的話是 Query OK, 50000 rows affected (13.26 sec)

最後採取每次刪 10,000 每 2~3 秒刪一次, 避免 cpu 飆高

INSERT 非常快無需擔心

COUNT(*) & COUNT(1) 初淺效能比較

先給結論: 無差別

測試環境: AWS RDS MySQL db.t2.small

Table 筆數: 近 570 萬

執行 query 所花時間差不多都是 0.75 秒

MySQL 常用指令

登入 mysql (使用 -p 密碼登入)

root@jex:/# mysql -u webadmin -p
root@jex:/# mysql -u webadmin --password=00000000 db_name

連入遠端 mysql

mysql -h devHostName -u jex -p
mysql>    #按ENTER是換第二行輸入,
          #不是送出而是繼續輸入,
          #如果不要再輸入了加上分號(;)表示結束
          #quit 或 ctrl + d : 中斷

進入 local mysql server (in docker)

mysql -h localhost -P 3306 --protocol=tcp -u root

匯入匯出資料庫

mysqldump 無法將密碼寫在指令上 e.g. --password=00000000, 所要要改用 config 的方式

/home/web-admin/db_backup/my.cnf:

    [mysqldump]
    password=00000000

mysqldump --defaults-file=/home/web-admin/db_backup/my.cnf --opt -u root my_db > my_db_backup.sql

匯出test資料庫, user為jex, 密碼送出才輸入, 匯出到目前的目錄, 檔案名稱為test_backup.sql

mysqldump --opt -u jex -p db_name > db_name_backup.sql

建立 test 使用者及建立 test 資料庫

mysql> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER ON *.* TO 'test'@'localhost' IDENTIFIED BY PASSWORD '*A8950BFBF9522A31DA227E7E1E751E2DC0691964' WITH GRANT OPTION;
mysql> create database db_name

匯入 test 資料庫 (不論是匯入 database 或是 table, 寫法都一樣)

mysql -u root -p db_name < db_name_backup.sql

匯出單筆 user 資料

mysqldump -u root my_db user -w "email='jex_lin@gmail.com'"

匯出 test DB, 無資料(但仍保留AUTO_INCREMENT)

mysqldump --opt -u jex -p --no-data test > test_backup.sql

如果使用 innoDB 可能會有 lock 情況造成無法匯出, 加上 --lock-tables=false

匯出 test DB 裡的 qq table, 無資料(但仍保留AUTO_INCREMENT)

mysqldump --opt -u jex -p --no-data test qq > test_qq_backup.sql

匯出 test DB 的 groups 資料表 uid=6 的資料

mysqldump -u root test groups -w "uid=6" > group_test.sql

匯出 test DB, 無資料, AUTO_INCREMENT重置

mysqldump -u jex -p --no-data --skip-add-drop-table test | sed 's/AUTO_INCREMENT=[0-9]*\b//' > test_backup.sql

匯出遠端 mysql 資料

mysqldump -h sqlserver.com -u me -p123 me_test user -w "name='jex'" > qq

Host : sqlserver.com
Account : me
Password : 123
DB : me_test
Table : user
WHERE 條件 : name='jex'

管理 MySQL 會用到的語法

看目前連到 MySQL 的 process

SHOW PROCESSLIST;
.. or ...
SHOW FULL PROCESSLIST;
+--------+----------+-------------------+-------+---------+------+----------+-----------------------+
| Id     | User     | Host              | db    | Command | Time | State    | Info                  |
+--------+----------+-------------------+-------+---------+------+----------+-----------------------+
| 530566 | api      | 10.0.21.49:43537  | my-log | Async commit | 1 | cleaned up | INSERT INTO `device_log` (`model`, `did`, `uid`, `mac`, `category`, `action`, `ip`, `log_date`, `occurred_at`, `created_at`, `timestamp_milli`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)

KILL PROCESS: 如果對 MySQL 下的指令造成 LOCK TABLE 或其他效能上的影響, 想取消的話, 可以刪除這個 process

先找出 process id

SHOW PROCESSLIST;
| 284349 | root      | 10.0.1.224:52018  | my-log     | Query   | 2568 | copy to tmp table               | ALTER TABLE `user` CHANGE `name` `name` VARCHAR(100) CHARACTER SET utf8 COLLATE |

mysql> kill 284349;
Query OK, 0 rows affected (0.00 sec)

Show schema threads

SELECT * FROM performance_schema.threads;

其他系統指令

SHOW ENGINE INNODB STATUS;
SHOW GLOBAL STATUS;

Show running queries

SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST WHERE COMMAND != 'Sleep';

Shows all queries running for 5 seconds or more:

SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST WHERE COMMAND != 'Sleep' AND TIME >= 5;

Show all running UPDATEs:

SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST WHERE COMMAND != 'Sleep' AND INFO LIKE '%UPDATE %';

目前連接 mysql 的數量

SHOW STATUS WHERE `variable_name` = 'Threads_connected';

最多可以同時幾個連線 (注意,如果超過這個數量,mysql 就會回 Too many connections 錯誤),如果使用 AWS RDS MySQL 要參考它不同 size 支援的 max_connections 量

SHOW VARIABLES LIKE 'max_connections';

MySQL version

SHOW VARIABLES LIKE "%version%";
或
select version();

binlog 是否開啟

SHOW VARIABLES LIKE 'log_bin';

slow query 是否開啟

SHOW VARIABLES LIKE '%slow%';

將執行過的 Query 寫到 log 檔

SET GLOBAL general_log = 'ON';

查詢指令使用index情況,在開頭加上EXPLAIN

XPLAIN SELECT *
FROM  `user_log`
WHERE uid =2

顯示系統狀態(詳細)

show status;

顯示系統狀態(簡單)

status;

查看自已的權限

mysql> show grants;

查看某個 user 的權限

show grants for jex@'localhost';

列出 mysql 的 user

mysql> select user, host from mysql.user;

查看權限

select * from mysql.user where user='jex';

查看 mysql 帳戶密碼及 host

select host, user, password from mysql.user;

mysql privileges

SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, EVENT, TRIGGER, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EXECUTE

查看 mysql 帳號

desc mysql.user;

新增 User

use mysql;
INSERT INTO user(host,user,password) VALUES('127.0.0.1','jex',password('qwer7890'));

限定權限

GRANT SELECT,INSERT,UPDATE,DELETE,CREATE ON testDB.* TO jex@localhost IDENTIFIED BY 'qwer7890';
FLUSH PRIVILEGES;

所有權限

GRANT ALL PRIVILEGES ON *.* TO jex@localhost IDENTIFIED BY 'qwer7890' WITH GRANT OPTION;
等於
GRANT ALL PRIVILEGES ON *.* TO jex@localhost IDENTIFIED BY PASSWORD '*9B25933BE82583D0F86E4AB11A340DE6A3611ACD' WITH GRANT OPTION;

Show cache

show variables like '%cache%';

直接操作時會用到的語法

顯示資料庫清單

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| exam               |
| mysql              |
| package            |
| performance_schema |
| phpmyadmin         |
| test               |
+--------------------+
7 rows in set (0.02 sec)

選擇資料庫

mysql> use test
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed

顯示資料表清單

mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| test           |
+----------------+
1 row in set (0.00 sec)

顯示table的欄位資訊

mysql> show columns from test;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| name  | varchar(40) | NO   |     | NULL    |                |
| hobby | varchar(40) | NO   |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

或者:

mysql> desc test;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| name  | varchar(40) | NO   |     | NULL    |                |
| hobby | varchar(40) | NO   |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

顯示資料表的 TABLE Schema

mysql> show CREATE table test;
+-------+------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                   |
+-------+------------------------------------------------------------------------------------------------+
| test  | CREATE TABLE `test` (
          `name` varchar(80) DEFAULT NULL
        ) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+-------+------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

顯示 user 開頭的 table 列表

SHOW tables like 'user%';

Create database

CREATE DATABASE db_name

Use database

USE db_name

Drop database

DROP DATABASE db_name

DROP TABLE IF EXISTS `info`;

Create table

CREATE TABLE table_name (no char(4), name char(10));

CREATE TABLE `info` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `model` varchar(20) COLLATE utf8_unicode_ci NOT NULL,
  `version` varchar(10) COLLATE utf8_unicode_ci NOT NULL,
  `url` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
  `create_time` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `version` (`model`,`version`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

Drop table

DROP TABLE table_name;

Rename table name

RENAME TABLE table_name TO tt;

Display database list

SHOW DATABASES;

Display table list

SHOW TABLES;

Show 各 table 的筆數, 容量等等

SHOW TABLE STATUS;

Display table detail

DESC table_name;

Show index of a table

SHOW INDEX FROM table_name;

Alter column

ALTER TABLE qq_tab CHANGE qq_col qq_col varchar(80) NOT NULL;

Add column

ALTER TABLE tt ADD phone varchar(40);

Primary key

ALTER TABLE gearman_queue ADD COLUMN `id` INT(10) UNSIGNED PRIMARY KEY AUTO_INCREMENT;

Replace

UPDATE table_name SET field=replace(field, "android", "iphone");
UPDATE `supe_spacenews` SET `message` = REPLACE(`message`,'要替換的文字','替換後的文字') WHERE `message` LIKE '%要替換的文字%'

將欄位改成 allow null

ALTER TABLE my_table MODIFY url varchar(100);

Show index

SHOW INDEX FROM my_table;

Foreign key

SET FOREIGN_KEY_CHECKS=0;
SET FOREIGN_KEY_CHECKS=1;

顯示 Table 的 Index

SHOW INDEX FROM users;

刪除資料表內的所有資料,並且重置AUTO_INCREMENT

TRUNCATE TableName

LIKE IN 語法怎麼辦? 使用 REGEXP

SELECT * FROM students WHERE name REGEXP 'bob|jex|joyce';

設定 AUTO_INCREMENT

ALTER TABLE tbl AUTO_INCREMENT = 5;

更新與 users.uid 的關聯 parent_id

UPDATE parents set parent_id = (SELECT uid from users where users.username = parents.parent) where parents.parent != ''

程式裡會用到的語法

INSERT

INSERT INTO test2 (name, passwd) VALUES ('jex', '123');

INSERT IF NOT EXISTS

INSERT INTO promote_grab (m_id)
SELECT (2)
FROM DUAL
WHERE NOT EXISTS(SELECT 1 FROM promote_grab WHERE m_id = 2)

插入 m_id = 2 到 promote_grab, 如果 promote_grab 不存在 m_id =2 :

INSERT IGNORE (if exists)

INSERT IGNORE INTO books (id, title, author, year_published) VALUES (1, 'Green Eggs and Ham', 'Dr. Seuss', 1960)

插入一樣的 index 如果已存在就會 ignore 不會噴 error

INSERT or UPDATE IF EXISTS

INSERT INTO table (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE name="A", age=19

INSERT Table to another one : 將 user 資料表的資料都 insert 到 user2 資料表 :

INSERT INTO `user2` SELECT * FROM `user`

Insert or Update

INSERT INTO student (id, name) VALUES('1', 'Jex') ON DUPLICATE KEY UPDATE name='Bob'

UPDATE

UPDATE question_options SET question_id = 20, optional_item = 5 WHERE id = 64;

UPDATE with EXISTS

UPDATE suppliers
SET supplier_name = (SELECT customers.customer_name
                     FROM customers
                     WHERE customers.customer_id = suppliers.supplier_id)
WHERE EXISTS (SELECT *
              FROM customers
              WHERE customers.customer_id = suppliers.supplier_id);

DELETE

DELETE FROM videos WHERE id=1;

DELETE with EXISTS

DELETE FROM suppliers
WHERE EXISTS (SELECT *
              FROM orders
              WHERE suppliers.supplier_id = orders.supplier_id);

將 time 欄位加30天

DATE_ADD(time, INTERVAL 30 DAY) AS after_time

select 特定時間

select * from device where date_format(update_time, '%Y-%m-%d') = '2014-10-23';

WHERE json 裡的欄位

SELECT * FROM `user` WHERE profile->"$.email" != ""                         // email 是欄位名稱
SELECT * FROM `user` WHERE profile->'$."example+11@example.com"' != ""      // 如果欄位名稱有符號要用 雙引號包起來

IFNULL(x, y): 如果 x 欄位的值是 NULl 就回傳 x, 否則是 y

GROUP BY IFNULL(ann_id, id)

FORCE INDEX 強制指定某個 index (寫在 from 前)

FORCE INDEX (uid+age+created_at)

LIMIT & OFFSET

// return only 10 records, start on record 16 (OFFSET 15)
SELECT * FROM Orders LIMIT 10 OFFSET 15
SELECT * FROM Orders LIMIT 15, 10

當資料筆數很大, 且 OFFSET 很大的話, 效能會很不好, 解決方式是不要用 OFFSET, 改用 PK id < 每次撈取的最後一個 id

UNION 將兩個不同表但欄位類似的 Query 合成一個結果

SELECT City FROM Customers
UNION
SELECT City FROM Suppliers
ORDER BY City;

如果只取一個欄位的話, UNION 預設會幫你去除重覆的, 如果要顯示重覆的話要用 UNION ALL

UNION + Unique 每個欄位

SELECT * FROM (
    SELECT City, Code FROM Customers
    UNION
    SELECT City, Code FROM Suppliers
    ORDER BY City;
) C
GROUP BY City

DISTINCT 沒有用, 要用 GROUP BY

JOIN

gui.JPG

A1

1 aaa
2 bbb

A2

1 bbb
2 ccc

Left join SELECT * FROM `A1` LEFT JOIN A2 ON A1.did = A2.did

id did id did
2 bbb 1 bbb
1 aaa NULL NULL

Right join SELECT * FROM `A1` RIGHT JOIN A2 ON A1.did = A2.did

id did id did
2 bbb 1 bbb
NULL NULL 2 ccc

Inner join SELECT * FROM `A1` INNER JOIN A2 ON A1.did = A2.did

id did id did
2 bbb 1 bbb

子查詢

限制

1) 不可以傳回兩個欄位以上

2) 不可以傳回兩筆以上的紀錄

SELECT *
FROM users
WHERE uid = (SELECT parent_id FROM parents WHERE student_id=1109 LIMIT 1)

其他

3-tier Category

+--------+---------------+-----------+
| cat_id | name          | parent_id |
+--------+---------------+-----------+
|      1 | Electronics   |         0 |
|      2 | Appliances    |         0 |
|      3 | Cell phones   |         1 |
|      4 | Computers     |         1 |
|      5 | Tablets       |         1 |
|      6 | Smartphones   |         3 |
|      7 | Tablet Phones |         3 |
+--------+---------------+-----------+

mysql> SELECT
    -> a.name AS main_category,
    -> b.name AS second_level_category,
    -> c.name AS thrid_level_category
    ->  FROM categories AS a
    -> LEFT JOIN categories AS b ON (a.cat_id=b.parent_id)
    -> LEFT JOIN categories AS c ON (b.cat_id=c.parent_id)
    -> WHERE a.parent_id=0;
+---------------+-----------------------+----------------------+
| main_category | second_level_category | thrid_level_category |
+---------------+-----------------------+----------------------+
| Electronics   | Cell phones           | Smartphones          |
| Electronics   | Cell phones           | Tablet Phones        |
| Electronics   | Computers             | NULL                 |
| Electronics   | Tablets               | NULL                 |
| Appliances    | NULL                  | NULL                 |
+---------------+-----------------------+----------------------+

Rails ORM 版

Category.from('categories AS a').where('a.parent_id = ?', 0).
         joins('LEFT JOIN categories AS b ON (a.id = b.parent_id)').
         joins('LEFT JOIN categories AS c ON (b.id = c.parent_id)').
         select('a.name AS main, b.name AS second, c.name AS third')

ref : http://stackoverflow.com/questions/21277663/mysql-normalization-with-category-with-1st-tier-sub-category-and-2nd-tier-sub-ca

LIKE 語法關鍵字 _ %

  • % : 0 個或以上的任意字元
  • _ : 只能有一個字元

How to prevent sql injection

  • 限制 db user 的權限
  • 使用程式提供的工具去過濾,也盡量避免以下字元進入到 query : ' " \ & * ;
  • 使用 Prepare 取代 query 的變數
  • 使用一些 SQL 的檢查工具 e.g. sqlmap, SQLninja
  • 避免將 SQL 錯誤發生時的資訊印出

支援儲存 unicode character(emoji,特殊字元)

utf8 vs utf8mb4

  • utf8 is a variable-length encoding. In the case of UTF-8, this means that storing one code point requires one to four bytes. However, MySQL’s encoding called “utf8” only stores a maximum of three bytes per code point.
  • utf8mb4 character set uses a maximum of four bytes per character

1) 將欄位改成 utfmb4_unicode_ci

2) 確認連線時的 Server charset, 如果預設是 UTF-8 Unicode (utf8), 那麼與 mysql 建立連線時的 dsn 就要加上 &charset=utf8mb4

SHOW VARIABLES WHERE variable_name LIKE 'character%' OR variable_name LIKE 'collation%'
  • The server character set and collation are the values of the character_set_server and collation_server system variables.
  • The character set and collation of the default database are the values of the character_set_database and collation_database system variables.
  • The server takes the character_set_client system variable to be the character set in which statements are sent by the client.

如果連線的 client connection 沒有使用 utf8mb4, 在撈含有特殊字元的資料不會 error, 但字元會變成 ?

Rsync 指令

本機同步資料夾

/tmp/destination/ 為主要, 將 /tmp/source/ 同步

rsync -avr --delete /tmp/destination/ /tmp/source/
  • -a, –archive archive mode; equals -rlptgoD (no -H,-A,-X)
  • -v, –verbose increase verbosity
  • -r, –recursive recurse into directories
  • –delete delete extraneous files from destination dirs
  • -e, –rsh=COMMAND specify the remote shell to use

將本機資料夾複製到遠端 projects/ 下

rsync -ae "ssh -p 9022" test jex@106.185.77.26:/home/jex/note/projects/

將遠端的 test 資料夾 sync 到 /tmp

rsync -av -e ssh jex@example.com:~/test/ /tmp
  • 注意!! test 資料夾後面一定要加/
  • 以上指令不會將 tmp 有但 test 沒有的檔案做刪除, 如果要與 test 完全一樣, 加上 --delete 參數即可

將本地的資料夾 sync 到遠端

rsync -av -e ssh /tmp/test jex@example.com:/tmp

同上, 不過指定金鑰

rsync -av -e "ssh -i .ssh/aws-me-tokyo.pem" ~/test ubuntu@my_web:/tmp

如果來源資料夾有些檔案刪除再去做同步後,目的資料夾是不會刪掉的原本存在的檔案,除非加上 --delete

同步到遠端, 指定 port

rsync -av --delete --checksum --rsh=/usr/bin/ssh /tmp jex:/tmp -e "ssh -p 3333"

-c, –checksum skip based on checksum, not mod-time & size

以 ssh rsync 到遠端, 如果資料夾不存在自動建立

rsync -avr --rsh='ssh -p41111' reporting/ jx@my-base:/home/m/reporting/
/usr/bin/rsync -rlpvz --delete --exclude-from=/tmp/exclude_file --checksum --rsh=/usr/bin/ssh /home/jex/code/ jex@remoteServer.com:/var/www/code -e "ssh -p 1234"

exclude

rsync -av --exclude 'modules/qq' --exclude 'modules/cc'  /home/jex/index /tmp/

exclude file

rsync -av --exclude-from=$HOME/exclude_file /home/jex/index /tmp/

$HOME/exclude_file :

.git
.gitignore
.htaccess

Linux 常用指令

快捷鍵

畫面

  • Ctrl + l : 清畫面, 等於指令 clear
  • Ctrl + z : 暫時停止程式(將該工作放到背景) (fg 1, fg 2 拿回)
  • Ctrl + c : 終止正在執行的程式
  • Ctrl + s : 停止輸出到畫面上(類似 Scroll Lock, ex: cat xxx 需暫停時使用)
  • Ctrl + q : 回復輸出到畫面上(恢復Ctrl+S的輸出)
  • Ctrl + d : 結束輸入(如果您在 shell 下,就會跳出該 shell)

刪除

  • Ctrl + w : 刪除游標前一段指令,依空白為段落
  • Ctrl + u : 刪除游標前的字
  • Ctrl + k : 刪除游標後的字
  • Ctrl + h : Backspace 鍵功能
  • Ctrl + d : Del 鍵功能

移動

  • Ctrl + a : 游標移到最前面
  • Ctrl + e : 游標移到最後面
  • Ctrl + f : 往右移一個字元, 相當右鍵
  • Ctrl + b : 往左移一個字元, 相當左鍵

指令

  • Ctrl + x 接著按 Ctrl + e : 可以使用 vim 寫入 script 讓他一次執行
  • Ctrl + r : 尋找之前輸入過的指令
  • Ctrl + p : 上一個指令, 相當上鍵
  • Ctrl + n : 下一個指令, 相當下鍵
  • Ctrl + i : 同 Tab
  • Ctrl + v + Tab : 輸入 Tab (空白)
  • Ctrl + j : 同 Enter
  • Ctrl + t : 相近兩個字元互換位置
  • Ctrl + - : undo
  • Ctrl + v : 再加上要輸入特殊字元, ex: 先按 Ctrl-V 再按 Ctrl-C 會出現 ^C 而不是中斷

其他

  • Alt + f : 到此行的後一個字
  • Alt + b : 到此行的前一個字
  • Alt + d : 刪除游標之後的一個單字
  • ESC + t : 最後 兩個 “單字” 互換位置
  • set -o : 可以列出所有 Mode
  • set -o vi : 可以用 vi 操作法來操作 Bash Shell(用此 Mode 上述的快速鍵即無作用)
  • set -o emacs : Bash 預設就是此 Mode.

使用者

線上使用者

$ who
webadmin pts/0        Apr 20 17:51 (61.58.172.120)
root     pts/1        Apr 20 18:46 (61.58.172.120)

$ w
18:46:50 up 103 days, 22 min,  1 user,  load average: 0.00, 0.00, 0.00
USER     TTY      FROM              LOGIN@   IDLE   JCPU   PCPU WHAT
webadmin pts/0    180-176-112-131. 18:40    0.00s  0.00s  0.00s w

目前使用者

whoami

自動建立階層目錄 recursive mkdir

mkdir -p /var/www/log/website

-p, –parents no error if existing, make parent directories as needed

md5

md5 test.txt
MD5 (test.txt) = b79a5759ca168122b9ebd1b57e4a883b

或

md5sum test.txt

ls

顯示目錄下的檔案權限, 擁有者..等等

ls -l

檔案大小那邊會換算成我們習慣的方式(G, M, K)

ls -lh
drwxr-xr-x 15 webadmin root 4.0K Mar 19 21:09 application
drwxr-xr-x  6 webadmin root 4.0K Apr  7 21:25 assets

顯示目錄下的檔案(包含隱藏檔)

ls -a

ls | more    # 分頁 q : 離開
ls | less    # 分頁 (操作如同vim,但不需要加ctrl)
             # d : 下12筆,
             # b、w : 上一頁,
             # f : 下一頁,
             # j 、e : 下一筆,
             # g : 回到第一筆,
             # k : 上一筆,
             # h : help

顯示檔案的inode id

$ ls -ia
1451762 .           1443270 .mysql_history  1576628 assets
1451760 ..          1443190 .php_history    1443160 djfl
1577046 .cache      1443425 .ssh            1443313 index.php
1443151 .git        1576655 .vim            1443315 license.txt
1443307 .gitconfig  1442269 .viminfo        1576661 system
1443272 .gitignore  1443276 .vimrc          1577048 test
1443312 .htaccess   1576553 application     1576831 user_guide

pwd

目前目錄位置

$ pwd
/home/ec2-user/my_project

如果是連結檔, 加上-P可以顯示真實路徑

$ pwd -P
/home/apps/src/my_project

cd

如果是連結檔, 加上-P可以進入到真實路徑

$ cd -P my_project/

tail

tail -f -n 100 log-2013-06-21.php     #當檔案發生變動時印出檔尾末100行

限制字數

tail -f log-2017-10-12.php | cut -c -80

scp 遠端複製檔案

一般用法 : 將本機檔案

$ scp .tmux.conf username@example.com:~/.tmux.conf

指定 port

scp -P 4123 remote_user@192.168.37.21:~/test/t.txt t.txt

使用vim為預設編輯器

export EDITOR=vim
export VISUAL=vim

chown

改變群組及擁有者

drwxr-xr-x 4 root     root 4096 Apr 20 18:46 test1        #原本擁有者及群組都是root

$ chown webadmin:webadmin test1                           #將擁有者及群組都改為webadmin
drwxr-xr-x 4 webadmin webadmin 4096 Apr 20 18:46 test1    #結果擁有者及群組都是webadmin

省略群組, 只會改擁有者

drwxr-xr-x 4 webadmin root 4096 Apr 20 18:46 test1          #原本擁有者為webadmin,群組為root

$ chown root test1                                          #只輸入root(省略群組)
drwxr-xr-x 4 root     root 4096 Apr 20 18:46 test1          #結果只會修改擁有者,群組不變

chgrp

drwxr-xr-x 4 webadmin webadmin 4096 Apr 20 18:46 test1      #原本群組為webadmin

$ chgrp root test1                                          #將群組改為root
drwxr-xr-x 4 webadmin root 4096 Apr 20 18:46 test1          #結果群組改為root了

chmod

改為 777

drwxr-xr-x 4 webadmin root 4096 Apr 20 18:46 test1          #原本權限為755

$ chmod 777 test1                                           #將權限改為777
drwxrwxrwx 4 webadmin root 4096 Apr 20 18:46 test1          #結果權限被改為777了

全部加上執行權限 (a+x)

-rw-r--r-- 1 webadmin root   20 Apr 21 11:18 test.php       #原本

$ chmod +x test.php                                         #全部都加上執行權限
-rwxr-xr-x 1 webadmin root   20 Apr 21 11:18 test.php       #結果

只有 user 加上執行權限

-rw-rw-rw- 1 webadmin root   20 Apr 21 11:18 test.php       #原本

$ chmod u+x test.php                                        #只有擁有者加上執行權限
-rwxrw-rw- 1 webadmin root   20 Apr 21 11:18 test.php       #結果
  • u 代表 user
  • g 代表 group
  • o 代表 others
  • a 代表 all

watch -n 1

每秒執行一次

watch -n 1 cat filename
watch -n 1 tail -5 /etc/projid
watch -n 1 'netstat -ant | grep "ESTABLISHED" | wc -l'

-n, –interval seconds to wait between updates

locale 列出語言檔

locale -a

screen

  • screen: 進入 screen 模式
  • screen -ls: screen list
  • screen -r: 連回 screen
  • screen -r 70346: 連回 screen 叫 70346 的 screen
  • ctrl + a + d: 離開 screen, 保持 screen 在背景運作
  • ctrl + a + t: 顯示目前系統的時間與負載狀況
  • ctrl + a + ?: 說明
  • ctrl + a + x: 鎖定螢幕
  • ctrl + a + C: 清除內容

視窗

  • ctrl + a + c: 建立新視窗
  • ctrl + a + n: 切換下一個視窗
  • ctrl + a + p: 切換上一個視窗
  • ctrl + x + shift + [ : 交換視窗位置
  • ctrl + a + w: 視窗 list
  • ctrl + a + ": 視窗 list 並且可以選擇要到哪一個
  • ctrl + a x 2: 切換到上次的視窗
  • ctrl + a + k: 關閉目前的視窗

分割視窗

  • ctrl + a + S: 水平分割視窗
  • ctrl + a + Q: 關閉分割視窗
  • ctrl + a + tab: 切換分割視窗

copy mode

  • ctrl + a + ESC or ctrl + a + [: 進入 copy mode
  • 第一次按空白鍵是複製的起點, 第二次按空白鍵是複製的結尾
  • ctrl + a + ]: 將複製的東西貼上

tmux

  • ctrl + b + " — split pane horizontally.
  • ctrl + b + % — split pane vertically.
  • ctrl + b + arrow key — switch pane.
  • Hold Ctrl+b, don’t release it and hold one of the arrow keys — resize pane.
  • ctrl + b + c — create a new window.
  • ctrl + b + n — move to the next window.
  • ctrl + b + p — move to the previous window.

ref: more shortcuts

uname

顯示作業系統

$ uname
Linux

顯示作業系統版本

$ uname -a
Linux ip-10-0-11-161 4.4.35-33.55.amzn1.x86_64 #1 SMP Tue Dec 6 20:30:04 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux

顯示幾位元

$ uname -m
x86_64 = 64 bit

i686 = 32 bit

test

test -e /dmtsai

[1] 關於某個檔名的『檔案類型』判斷,如 test -e filename 表示存在否

  • -e 該『檔名』是否存在?(常用)
  • -f 該『檔名』是否存在且為檔案(file)?(常用)
  • -d 該『檔名』是否存在且為目錄(directory)?(常用)
  • -b 該『檔名』是否存在且為一個 block device 裝置?
  • -c 該『檔名』是否存在且為一個 character device 裝置?
  • -S 該『檔名』是否存在且為一個 Socket 檔案?
  • -p 該『檔名』是否存在且為一個 FIFO (pipe) 檔案?
  • -L 該『檔名』是否存在且為一個連結檔

[2] 關於檔案的權限偵測,如 test -r filename 表示可讀否 (但 root 權限常有例外)

  • -r 偵測該檔名是否存在且具有『可讀』的權限?
  • -w 偵測該檔名是否存在且具有『可寫』的權限?
  • -x 偵測該檔名是否存在且具有『可執行』的權限?
  • -u 偵測該檔名是否存在且具有『SUID』的屬性?
  • -g 偵測該檔名是否存在且具有『SGID』的屬性?
  • -k 偵測該檔名是否存在且具有『Sticky bit』的屬性?
  • -s 偵測該檔名是否存在且為『非空白檔案』

[3] 兩個檔案之間的比較,如: test file1 -nt file2

  • -nt (newer than)判斷 file1 是否比 file2 新
  • -ot (older than)判斷 file1 是否比 file2 舊
  • -ef 判斷 file1 與 file2 是否為同一檔案,可用在判斷 hard link 的判定上。 主要意義在判定,兩個檔案是否均指向同一個 inode 哩!

[4] 關於兩個整數之間的判定,例如 test n1 -eq n2

  • -eq 兩數值相等 (equal)
  • -ne 兩數值不等 (not equal)
  • -gt n1 大於 n2 (greater than)
  • -lt n1 小於 n2 (less than)
  • -ge n1 大於等於 n2 (greater than or equal)
  • -le n1 小於等於 n2 (less than or equal)

[5] 判定字串的資料

  • test -z string 判定字串是否為 0 ?若 string 為空字串,則為 true
  • test -n string 判定字串是否非為 0 ?若 string 為空字串,則為 false。

註: -n 亦可省略

  • test str1 = str2 判定 str1 是否等於 str2 ,若相等,則回傳 true
  • test str1 != str2 判定 str1 是否不等於 str2 ,若相等,則回傳 false

[6] 多重條件判定,例如: test -r filename -a -x filename

  • -a (and)兩狀況同時成立!例如 test -r file -a -x file,則 file 同時具有 r 與 x 權限時,才回傳 true。
  • -o (or)兩狀況任何一個成立!例如 test -r file -o -x file,則 file 具有 r 或 x 權限時,就可回傳 true。
  • ! 反相狀態,如 test ! -x file ,當 file 不具有 x 時,回傳 true

Cat

Append one file to another

cat d.txt >> q.txt

顯示檔案內容及行數

cat -n phpinfo.php

whereis

尋找檔案

$ whereis bin
bin: /usr/local/bin

whereis 利用曾經找過的系統資訊內的資料去找檔案,所以速度會很快 * 不過,如果 whereis 找不到的話,並不代表該檔案真的不存在!

系統資訊

系統訊息

$ cat /etc/*release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=13.04
DISTRIB_CODENAME=raring
DISTRIB_DESCRIPTION="Ubuntu 13.04"
NAME="Ubuntu"
VERSION="13.04, Raring Ringtail"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 13.04"
VERSION_ID="13.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"

看系統內核等信息

$ uname -a
Linux virtualBox 3.8.0-30-generic #44-Ubuntu SMP Thu Aug 22 20:52:24 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux

查看系統資訊

$ more /proc/version
Linux version 2.6.32-042stab059.7 (root@rh6-build-x64) (gcc version 4.4.6 201203
05 (Red Hat 4.4.6-4) (GCC) ) #1 SMP Tue Jul 24 19:12:01 MSK 2012

等同 cat /proc/version

查看目前Linux版本

$ cat /etc/issue
Ubuntu 12.04.1 LTS \n \l

顯示linux版本

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 12.04.1 LTS
Release:        12.04
Codename:       precise

ps aux 查看 process 狀態

  • ps aux : 查看目前系統所執行的程式
  • ps aux --sort -rss : Show memory usage from highest to lowest.

看 process 的啟動及持續時間

ps -eo pid,comm,lstart,etime,time,args

PID COMMAND                          STARTED     ELAPSED     TIME COMMAND
  1 init            Thu Sep 21 10:38:33 2017 11-22:21:26 00:00:01 /sbin/init
  2 kthreadd        Thu Sep 21 10:38:33 2017 11-22:21:26 00:00:00 [kthreadd]
  3 ksoftirqd/0     Thu Sep 21 10:38:33 2017 11-22:21:26 00:00:00 [ksoftirqd/0]

欄位名稱代表的意義

  • USER = user owning the process
  • PID = process ID of the process
  • %CPU = It is the CPU time used divided by the time the process has been running.
  • %MEM = ratio of the process’s resident set size to the physical memory on the machine
  • VSZ = virtual memory usage of entire process (in KiB)
  • RSS = resident set size, the non-swapped physical memory that a task has used (in KiB)
  • TTY = controlling tty (terminal)
  • STAT = multi-character process state
  • START = starting time or date of the process
  • TIME = cumulative CPU time
  • COMMAND = command with all its arguments

顯示所有partition

sudo fdisk -l

其他

  • sudo shutdown -r now :重開機
  • sudo reboot : 重開機
  • sudo shutdown -h now : 關機
  • top : cpu 使用率
  • ps -l : 僅觀察自己的 bash 相關程序

背景執行

放入背景

ctrl + z

看背景有哪些程式在執行

$ jobs
[1] + Stopped                    vim test

叫出第一個背景的程式

$ fg %1

停止在背景執行的第一個程式

$ kill -9 %1
$ jobs
[1] + Killed                     vim test

強制中斷 process

kill

kill 11372 (pid)
    -9       KILL (non-catchable, non-ignorable kill)

killall (kill processes by name)

killall redis

查看 Process 是否執行中(其實就是看有沒有 pid)

pidof redis
  • SIGHUP (1) - terminal line hangup
  • SIGINT (2) - interrupt program
  • SIGQUIT (3) - quit program
  • SIGKILL (9) - kill program
  • SIGTERM (15) - software termination signal
  • SIGSTOP (17) - stop (cannot be caught or ignored)
  • SIGTSTP (18) - stop signal generated from keyboard

lsusb

列出連接 usb 的週邊設備

$ lsusb
Bus 001 Device 002: ID 80ee:0021 VirtualBox USB Tablet
Bus 001 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub

apropos

apropos searches a set of database files containing short descriptions of system commands for keywords and displays the result on the standard output.

$ apropos awk
a2p(1)                   - Awk to Perl translator
awk(1)                   - pattern-directed scanning and processing language
English(3pm)             - use nice English (or awk) names for ugly punctuation variables
a2p(1)                   - Awk to Perl translator
awk(1)                   - pattern-directed scanning and processing language

cpu info

$ cat /proc/cpuinfo
processor       : 0
vendor_id       : GenuineIntel
cpu family      : 6
model           : 45
model name      : Intel(R) Xeon(R) CPU E5-2650 0 @ 2.00GHz
stepping        : 7
microcode       : 0x70a
cpu MHz         : 1799.999
cache size      : 20480 KB
(...略...)

Memory info

$ free -h
             total       used       free     shared    buffers     cached
Mem:          3.8G       3.2G       646M         0B       1.1G       1.3G
-/+ buffers/cache:       914M       3.0G
Swap:         4.0G       121M       3.9G

cpu core count

nproc
或
cat /proc/cpuinfo | grep process

cpu information

lscpu
或
cat /proc/cpuinfo

wc 程序從標準輸入流或文件列表讀取文件,並生成一個或多個下列統計信息

  • wc -l <文件名> 輸出行數統計
  • wc -c <文件名> 輸出位元組數統計
  • wc -m <文件名> 輸出字元數統計
  • wc -L <文件名> 輸出文件中最長一行的長度
  • wc -w <文件名> 輸出單詞數統計

count line

netstat -ant | grep "ESTABLISHED" | wc -l
wc -l import.txt

count file characters

wc -c off.xml

less color

ls --color | less

結果 :

ESC[0mESC[01;34mc1ESC[0m
ESC[01;34mc2ESC[0m
ESC[01;34mc3ESC[0m

加上 -R, 結果就會有顏色了

 --color | less -R

-R or –RAW-CONTROL-CHARS : Like -r, but only ANSI “color” escape sequences are output in “raw” form. Unlike -r, the screen appearance is maintained correctly in most cases.

sudo command not found

有時候拿 sudo 去執行某些指令時, 會發生此問題, 因為 sudo 並沒有設定那些指令的路徑, 把它加上去即可

sudo env PATH=$PATH

檔案字尾出現 windows 換行符號 ^M

因為 windows 與 linux 字尾符號不同的關係, 可藉由 dos2unix 修正

基本用法

dos2unix t1.php t2.php t3.php

修正所有檔案(recursive)

find . -type f -exec dos2unix {} \;

或用 vim 修正, 但僅限於可以看到 ^M 在字尾

:%s/\r//g

如果用 vim 開啟看不到 ^M 在字尾要改用

sed -i 's/\r$//' wrap-trim.log

cowsay

jex@jex:/tmp$ echo "Hello World!" | cowsay
 ______________
< Hello World! >
 --------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

jex@jex:/tmp$ echo "????????????" | cowthink
 ______________
( ???????????? )
 --------------
        o   ^__^
         o  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

ulimit

設定每個 user 能使用的資源 e.g. 開檔數量

  • -a : 列出所有 user 的限制
  • -H : Hard limit 絕對不能超過這個值
  • -S : Soft limit 可以超過,但會有警告
  • -d : process 可使用的最大容量
  • -f : 不加參數會回傳限制的大小,加上數值會設定 process 可以建立的最大檔案的容量 (單位: Kbytes)
  • -p : 可用 pipe 的數量
  • -l : 可用於 lock 的記憶體量
  • -t : 可使用的最大 CPU 時間 (秒)
  • -u : 某一 User 可使用的最大 process 數量
  • -n : Specifies the limit on the number of file descriptors a process may have

To set the size of core dumps to unlimited, use:

ulimit –c unlimited

uptime

server 總共執行多久了

 10:53:24 up 34 days,  7:47,  1 user,  load average: 0.09, 0.06, 0.06

load average 代表是系統的平均負荷

後面的3個數字分別代表 1, 5, 15 分鐘。0 CPU 空閒, 1 代表 cpu 滿載, 數值有可能會大於 1

date

輸出 timestamp

date +%s

timestamp to datetime

date -d @1481605585
Tue Dec 13 05:06:25 UTC 2016

datetime to timestamp

date -d '2018/05/09 09:30:30' +"%s"
date -d 'TZ="UTC+9" 2018-07-04 02:53:06' +%s   // 會幫你把 datetime +9 再轉成 timestamp
date -d 'TZ="UTC-9" 2018-07-04 02:53:06' +%s   // 如果 datetime 是日本時間, 再轉成 timestamp 這樣才對

開機自動執行

/etc/rc.d/rc.local :

touch /var/lock/subsys/local   # 原本就存在的,新增的寫在下面
/etc/init.d/nginx start
/etc/init.d/php-fpm start

lsof

檔案刪除了, 空間卻沒有被釋放, 還是被維持 open 的狀態, 所以空間釋放不了, 用這個指令查可以把它找出來, 再把這個 process kill 掉就行了

sudo lsof | grep deleted

my-monitor    8172  9770       root  156r      REG              202,1 1359484070     276282 /home/apps/example/test.log (deleted)
my-monitor    8172  9770       root  163r      REG              202,1 1359484070     276282 /home/apps/example/test.log (deleted)
my-monitor    8172  9770       root  191r      REG              202,1 1359484070     276282 /home/apps/example/test.log (deleted)
my-monitor    8172  9770       root  212r      REG              202,1 1359484070     276282 /home/apps/example/test.log (deleted)
my-monitor    8172  9770       root  214r      REG              202,1 1359484070     276282 /home/apps/example/test.log (deleted)
my-monitor    8172  9770       root  226r      REG              202,1 1359484070     276282 /home/apps/example/test.log (deleted)

free up memory

linux:

echo 3 > /proc/sys/vm/drop_caches
  • 1: pagecache
  • 2: dentries and inodes
  • 3: 1 + 2

mac:

sudo purge

hexdump: 將檔案(一般檔案或 binary) 輸出成 16 進制

-C 輸出三列(文字偏移量,16進制,ASCII)

hexdump -C test.txt
00000000  30 31 32 33 34 35 36 37  38 39 41 42 43 44 45 46  |0123456789ABCDEF|
00000010  47 48 49 4a 4b 4c 4d 4e  4f 50 51 52 53 54 55 56  |GHIJKLMNOPQRSTUV|
00000020  57 58 59 5a 0a                                    |WXYZ.|
00000025

最後的 0a 是換行字元, 可用 ASCII 對應表來看

xxd: 將檔案輸出成 16 進制或 2 進制

不加參數, 輸出成 16 進制

xxd test.txt
0000000: 3031 3233 3435 3637 3839 4142 4344 4546  0123456789ABCDEF
0000010: 4748 494a 4b4c 4d4e 4f50 5152 5354 5556  GHIJKLMNOPQRSTUV
0000020: 5758 595a 0a                             WXYZ.

-b 輸出成 2 進制

xxd -b test.txt
0000000: 00110000 00110001 00110010 00110011 00110100 00110101  012345
0000006: 00110110 00110111 00111000 00111001 01000001 01000010  6789AB
000000c: 01000011 01000100 01000101 01000110 01000111 01001000  CDEFGH
0000012: 01001001 01001010 01001011 01001100 01001101 01001110  IJKLMN
0000018: 01001111 01010000 01010001 01010010 01010011 01010100  OPQRST
000001e: 01010101 01010110 01010111 01011000 01011001 01011010  UVWXYZ
0000024: 00001010

最後的 00001010 = Hexadecimal 0a 是換行字元

SSH 連到本機的VirtualBox

讓本機的 putty 可以連進 VirtualBox 裡

  1. 開啟你的 windows 命令列輸入 ipconfig ,乙太網路卡 VirtualBox Host-Only Network: 的 IPv4 位址 那欄,假設是192.168.0.100,先記下來
  2. 開啟你的 linux terminal 輸入 ifconfig ,找到 inet addr,假設是10.0.3.11,先記下來
  3. 開啟VitualBox左上角機器設定值→網路→連接埠傳送
  4. 將你記下來的 IP 填上去。(主機IP是填windows IP,客體IP是填VirtualBox裡的Ubuntu IP)

     協定 : TCP
     主機IP : 192.168.0.100
     主機連接埠 : 22
     客體IP : 10.0.3.11
     客體連接埠 : 22
    
  5. 接下來打開 putty 連到 virtualBox

  6. Host Name (or IP address) 輸入 :192.168.0.100 (putty:要連的是主機ip)
  7. Port : 22

本機瀏覽器顯示 VirtualBox 裡 http server 結果

  1. 開啟VitualBox左上角機器設定值→網路→連接埠傳送
  2. 填入你的IP資訊,與上面設定幾乎一樣,但有兩部份需要更改

     協定 : TCP
     主機IP : 192.168.0.100
     主機連接埠 : 80
     客體IP : 10.0.3.11
     客體連接埠 : 80
    
  3. 本機網頁執行 http://192.168.0.100/ 即可

本機連到 virtualBox 裡的 samba

[1] 網路→介面卡→附加到選擇「僅限主機」介面卡

[2] virtualBox裡的主機要重新取得ip :

sudo service networking restart
ifconfig

[3] 就可以在本機連到virtualBox裡的samba :

\\ip\share

virtualbox 開多個 instance 並串成區網

將一個已安裝完 openssh-server ubuntu 的主機複製 3 份, 並且每台網路都設定 -> 網路 -> 附加到 橋接介面卡

再將每台主機開機並且指定不同的固定 IP (注意不要和本機的 Lan IP 重覆)

/etc/network/interfaces :

iface eth0 inet static
address 192.168.1.3
netmask 255.255.255.0

並且重啟 sudo service networking restart

這時候 本機及各主機就可以直接 ssh 到各主機了, 而不必透過 NAT 做 Port Forwarding 了

參考來源: 夯哥