2017年11月28日 星期二

Shell script 快速入門

第一行是 #!/bin/bash/
bin/bash 是大部人用的,也是預設的 shell,可看 /etc/passwd 的最後一個欄位


※參數

假設檔名叫 xxx.sh,下 xxx.sh aa bb
$#:表示有幾個參數,此例為 2
$0:xxx.sh,也就是檔名
$1:aa
$2:bb
一直到$9,10以上要用 {} 包起來,如 ${12}
$*:表示所有參數,整個參數是一個整體,如"$1 $2 $3",參數和參數之間用空隔隔開
$@:也表示所有參數,但每個參數是分開的,如 "$1" "2" "$3",參數和參數之間用空隔隔開
以上兩個需視情況用「"」包起來使用
$$:processID,ps -aux 可查看
$?:讀取上一行指令有沒有錯誤,沒錯回傳0,否則回傳錯誤代碼,最多255,如果超過255,那就是除 256 的餘數
man bash ,搜尋  ^exit status

※test.sh
#!/bin/bash
echo $#
echo $@
echo $0
echo $1
echo $$
echo $?
#echo xxx "aaa" "bbb"

xxx(){
    echo $1 $2
}
xxx "aaa" "bbb"

※./test.sh a b cccc de 結果為
4
a b cccc de
test.sh
a
547
0
aaa bbb

※./和sh可執行shell,但./需要w權限


※變數

a=apple(=前後不可有空格,字串有空格時,用「'」或「"」包起來)
echo $a 印出a變數
export aaa 將aaa變數提升為系統變數
source xxx 因為提升為系統變數後,要重登入才有效,懶得重登入就可用這個指令
unset xxx 刪除xxx變數

「`」鍵盤左上角下來一格的按鍵,可用這個包指令,然後串接字符串
如:echo xxx `date` ooo


四則運算(+-*/%)和test

$a+$b 用 $(( 和 )) 包起來,然後裡面的$可有可無-> $((a+b))
無法用小數點

${#a}:長度
${a:2}:最前面扣2長
${a:2:4}:最前面扣2長後,取4長
${a#a*c}:從前面開始刪除abc,刪一次(勉強)
${a##a*c}:從前面開始刪除abc,(貪婪)
${a%a*c}:從後面開始刪除abc,刪一次(勉強)
${a%%a*c}:從後面開始刪除abc,(貪婪)


test

-f -d -r -w -x
test -f $f && echo "is a file" || echo "isn't a file"
&& || 為三元運算子


[]

1.前後必需空格
2.變數要用「"」包起來
[ "$a" == '5' ] && echo "yes" || "no"
== != -eq -ne -gt -ge -lt -le


※條件

if

read xxx

if [ "$xxx" == '1' ]; then
elif []; then
else
fi

/proc/cpuinfo
/proc/meminfo

-a 且
-o 或

if [ "$xxx" == 'a' -o "$xxx" == 'd' -o "$xxx" == 'xx' ]


case

read n
case "$n" in
'a') echo 'aaa';;
'b') echo 'bbb';;
  *) echo '***';;
esac


※陣列

xxx=("aaa" "bbb" "ccc")
echo length:${#xxx[@]}
for((i=0; i<${#xxx[@]}; i++)); do
      echo ${xxx[i]}
done

※迴圈

while

while 條件; do

done;

while [ "$i" -le 10 ]; do
  echo "$i"
  i=$((i+1))
done


until

#觀念和 while 相反,判斷式為 true 時停止
until 條件; do

done;

until [ "$i" -gt 10 ]; do
  echo "$i"
  i=$((i+1))
done

for

for (()); do
  內容
done;

for ((i=0;i<10;i++)) do
  echo "$i"
done

for in

for x in aaa bbb ccc; do
  echo "$x"
done

2017年11月27日 星期一

linux 用戶指令快速入門

※一般命令

echo xxx && ooo
ls  -l    --all = -a    --human-readable = -h  --inode = -i,看多檔用空隔隔開
pwd
whoami
cd
tree
date '+%Y/%m/%d %H:%M:%S',%a %b %Z
cal
mkdir
rmdir:刪除空目錄
cp --recursive = -r   --interactive = -i:windows為 xcopy /E /H 
mv --interactive = -i:windows為 move
rm --recursive = -r   --interactive = -i:
      windows 分兩步,為 [del|erase] /S /Q bbb && [rmdir|rd] /S /Q bbb 
touch xxx.txt,windows 為 type nul > xxx.txt
man: see also -> man [number] command
cat --number = -n
tac
tty
history    !!:上一個命令     !c:最接近c開頭命令    !號碼
file 查看是什麼檔案
more
less

grep,過濾結果,windows 有類似的,如 netstat -ano |find ":80"
-A -B -C 還蠻好用的
cat xxx.txt |grep abc -A 5:表示找xxx.txt裡有abc這行和之後的5行,找到多個會用「--」隔開
-B:之後
-C:前後,可以不打-C,直接打數字即可

|
head -行數,預設 10 行
tail -行數 --follow = -f:f 不能和 -行數一起使用,功能是畫面停住,等待新的訊息進來,然後顯示,Ctrl + c 可離開
ln


※vim

visual(視覺的) improved(改進過的),因為原本是 vi,改進過後是 vim
man vi 可查參數,再按 h 可查文檔

命令模式

剪下:[number]D
複製:[number]yy,yank 為使勁拉的意思
貼上:[number]p
刪除:[number]dd
上一次修改:u
下一次修改:Ctrl + r
上一頁:Ctrl + b (before)
下一頁:Ctrl + f (after)
到某一行:ngg 或打「:」加行數

切換成編輯模式:a、i、o、A、I、O
切換成搜尋取代模式::、/、?


編輯模式

回命令模式:Esc


搜尋取代模式

:

數字:跳到某一行
set nu:顯示行號,如果想一進去就有行號,可用臨時的 vi -c "set nu" 檔名,或用永遠的方法,在 ~裡,創建 .vimrc 或 .virc 檔案,將 set nu 打進去存檔,這樣以後開所有檔都有行號了,是針對當前使用者的設定,vi 開頭的用 vi; vim 開頭的 用 vim,當然也可以兩個檔案都打
set nonu
set ignorecase:預設搜尋、取代時,是有分大小寫的,可打上這個命令來忽略大小寫
set noignorecase
set nohl:no high light,搜尋完後,下次進去,預設會高亮,可用這個指令
w
q
q!

取代,如「1,$s/xxx/ooo/gci」,第一行到最後一行,將 xxx 取代成 ooo
    「.,$s/xxx/ooo/gci」:目前行到最後一行
    「%s/xxx/ooo/gci」:第一行到最後一行,和 1,$s 一樣
g 為全部取代,沒加只取代一個
c 為檢查,會有 y/n/a/q/l/^E/^Y 的提示,yn就不說了
    a 表示目前到之後都取代
    q 表示不取代,並且直接離開
    l 表示取代目前這一個,並且直接離開
    ^E 表示跳上一頁
    ^Y 表示跳下一頁
    但 ^E 和 ^Y 我不知道要怎麼按
i 為不區分大小寫,也可用 上面的 set ignorecase

:2,10y:複製 2~10 行
:2,10d:剪下 2~10 行
:2,10y co 15:複製 2~10 行並貼到 15 行
:2,10y m 15:剪下 2~10 行並貼到 15 行

/

尋找,如「/xxx」,搜尋 xxx,然後使用 n|N可往下往上搜尋
搜尋完整單字,如 do、doc、dock,使用 /do 時,三個都會找到
可用 /\<do\>,使用「<」「>」包起來,但要用跳脫字元「\」就可以找完整的單字
又如果下/\<[dD]o\>,那會找 do 和 Do

?

同 / 的尋找,但一開始是下往上尋找,一樣用n|N找


回命令模式:Esc

多檔編輯

vim -o,水平,使用 Ctrl + w 後,按左或右切換
vim -O,垂直,使用 Ctrl + w 後,按上或下切換
vim -p 檔一 檔二,命令模式使用 :tabn 或 :tabp 切換
vim 檔一 檔二,命令模式使用「:sp 檔名」,然後使用 Ctrl + w ,上或下切換


※alias

alias vim='vim --cmd "set nu"',但登出後就沒了
將上一行打在 ~/.bashrc 裡,然後使用 source ~/.bashrc 或者下次登入就會生效了
unalias 為相反的命令

/etc/profile 全域環境變數     ~/.bash_profile 使用者環境變數
/etc/bashrc 全域 bash shell    ~/.bashrc 使用者 bash shell


※標準輸出入、標準錯誤輸出

< 檔案
<< 文字結束
>、1>
>>、1>>
2>、>&
2>>、>>&
&>

wc < /etc/passwd 行、單字、容量
wc < test1 >> test2


※搜尋

which:查尋環境變數的可執行程序,結果只有路徑
whereis:自訂的資料庫,結果有可執行命令 設定檔 手冊
locate:自訂的資料庫(var/lib/mlocate),比 whereis 更詳細,模糊查尋
find:最後的絕招, find /home -name xxx
find 後面接要搜尋的路徑,不打就是當前的路徑
-atime
-mtime 3 前三天的那一天,檔案內容有被修改過的
  +3 3天之外
  -3 3天之內
-ctime

-user 帳號名
-group 用戶組
-nouser 不屬於任何用戶
-nogroup 不屬於任何用戶組

-name 檔名或目錄名,可用通配符,但要用「'」包起來,如 '*bru*'
-iname 檔名或目錄名(不分大小寫)

-type f,查找檔案,l、d為連結和目錄
-size +100k:大於等於100K的文件
-perm +7000:找特殊權限
-exec 找到後執行命令,一直找到「;」之前
{}:會被替換當前的檔名
\:每個系統的「;」有可能有不同的意義,所以加上這個跳脫字元
例:
find -name 'test[34]' -exec sed -i 's/aaa/zzz/g' {} \;
sed 指令說明
find 指令說明

搜檔案內容
find /etc -name "*.text" -exec grep -H "xxx" {} \; 在 /etc 下搜尋 .text 結尾的檔案,內容含有 xxx的,--with-filename = -H 為列出路徑


※ls -l  的訊息

drwx-w--wx 2 bruce root 4096

d、-、l 目錄 檔案 連結

rw-r-x-wx
三個一組,分別表示權限,擁有者 群組 其他

目錄
r:查看目錄內容
w:增刪改
x:進入目錄

檔案
r:查看檔案內容
w:增刪改
x:執行

2 為檔案數量,目錄至少有.和..,不包括子目錄;檔案一定是 1
擁有者是誰
群組名
檔案大小(Byte)
Mtime
檔名

除了 root 外,擁有者、群組、其他人只能有一個角色
例如有一個使用者,是 A 檔的擁有者也是群組,此時若擁有者的權限不足,並不會抓群組的權限

※mtime、ctime、atime 區別

mtime:檔案內容最後被修改的時間,ls -l
ctime:檔案的內容、屬性最後被修改的時間,如修改權限、修改擁有者、改檔名,ls -cl
atime:最後被讀取的時間,vi 開啟就會讀到了,但 echo 不會讀到,ls -ul,但在安裝作業系統時可以選擇不要更新 atime,可以增進效能


※su、su -、sudo

su:切換成 root,shell 不切換
su -:切換成 root,shell 也切換
以上兩個後面如果接使用者,就會切換到那個使用者,輸入的密碼為切換帳號的密碼

sudo:臨時切換成 root,必需先設定 /etc/sudoers,可用 vi /etc/sudoers 或者 visudo 編輯,
輸入的密碼為自己的密碼

帳號     來源主機名稱=(可切換的身份)     能下什麼指令(絕對路徑)
root ALL=(ALL) NOPASSWD: ALL
root 這個帳號從任何主機連進來都可用現在的設定,可切換任何身份執行任何命令
其中(ALL) 和 NOPASSWD: 可以不寫
(ALL) 表示切換哪個帳號的身份,不寫就是 root,ALL 表示任何帳號
NOPASSWD: 注意最後有個冒號,不寫預設是要打密碼的,打登入時的密碼,不是切換誰的密碼

xxx 192.168.0.1=(ooo) /aaa/bbb,/aaa/ccc
xxx 這個帳號從 192.168.0.1 這台主機連進來可用現在的設定,可切換成 ooo 
這個帳號,執行 /aaa/bbb 和 /aaa/ccc 這兩支程式

%zzz ALL=(ALL) ALL
加上「%」就變成群組了
zzz這個群組從任何主機連進來都可用現在的設定,可切換任何身份執行任何命令

sudo 指令說明



※背起來

rsync -avzhpr

a --archive
v --verbose
z --compress
h --human-readable
p --perms:preserve permissions
r --recursive


tar -zxvf -cvf

c --create
z --gunzip
x --extract
v --verbose
f --file

.tar.gz -> zxvf
.tar -> xvf
cvf -> 打包

rpm -ivh -Uvh -qa -e

i --info
h --hash
U --upgrade
q --query
a --all
e:erase,御載

rpm -Uvh
rpm -qa |grep httpd

rpm 必須自己解決依賴關係


yum [-y] [install | remove | update | search | list | list installed]

search:列出伺服器上可貨下載的
list:列出伺服器上可供下載和已安裝的
list installed:列出已安裝的
update:更新某個套件,如果後面不加套件,會整個系統更新

yum 底層還是 rpm,但會幫我們解決依賴關係



編譯

下載源碼後,如 nginx,然後 wget xxx 並解壓後進目錄
./configure --prefix=/xxx/ooo
make && make install
以上三步搞定,但有時候第一步有依賴問題會報錯,根據報錯的訊息下載,然後再重做一次,只要有錯就得重做
※「./」開頭是一定要加的,通常環境變數不會有設定你下載的路徑,在 linux 裡,只要是執行檔就是綠色的,執行時環境變數沒有時,就要加「./」,表示當前層
但有六個目錄例外:
bin
usr/bin
usr/local/bin

sbin
usr/sbin
usr/local/sbin

有錯時,如沒有 pcre,那就在下載時,後面加上 -devel,是 develop 的簡寫,通常開發會比較多東西
yum -y install pcre-devel

搞定後,去 --prefix 的目錄查看



2017年11月18日 星期六

設定 java 版本 (Maven 6)

官網文件

※方法一

<properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
</properties>

※為什麼有 compilerVersion?可以到這篇看看


※方法二

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
    </plugins>
</build>

※我試了官方的不行,還得把 version 刪除才可以


※方法三

<profiles>
    <profile>
        <id>javaVersion</id>
        <properties>
            <maven.compiler.source>1.8</maven.compiler.source>
            <maven.compiler.target>1.8</maven.compiler.target>
            <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
        </properties>
        <!-- <activation> -->
        <!--     <activeByDefault>true</activeByDefault> -->
        <!-- </activation> -->
    </profile>
</profiles>
<activeProfiles>
    <activeProfile>javaVersion</activeProfile>
</activeProfiles>

※前面兩個方法都是在 pom.xml 設定,最好是在父 pom 設定,其他子 pom 就不用設了

※這個方法是在 settings.xml 設定,是全域的

※profile 寫好後並沒有生效,用 activeProfiles 標籤和註解的 activation 標籤都可以

2017年11月13日 星期一

私服 (Maven 5)

私人伺服器,簡稱私服



左邊為電腦,右邊為 maven central,中間為私服,每次都要連到 maven central 太慢了,所以才會架設中間的私服,讓每一台電腦用,如果私服沒有,那私服會去下載

如果只有一台電腦,那就沒差了,但可以練習用

此篇用的私服是 Sonatype Nexus,下載 OSS 版的來練習,這裡用的是 nexus-3.2.1-01-win64
下載解壓後會有兩個資料夾,將 nexus-3.2.1-01 資料夾裡的 bin 加到環境變數,然後執行 nexus /run,啟動有點久,出現了「Started Sonatype Nexus OSS 3.2.1-01」不要關掉,然後到 localhost:8081,預設帳密是 admin/admin123,可看官網文件的 Part1
換 port 可以到 nexus-3.2.1-01\etc\nexus-default.properties 改

type 有三種
group:可以將以下兩個類型,一個類型包括很多網址,可以合併成一個
hosted:本地倉庫
proxy:代理倉庫(maven-central)


1的圖示要登入才有,左圖的 Security \ Users 預設只有 admin 和 anonymous,可以先將 anonymous 關閉,也可以在這新增使用者、修改密碼…等操作


第 2 版可以全拉,但第 3 版不知道為什麼不行,只好拉二個了

maven-central 裡有個 Rebuild index 按鈕,因為一開始 本地倉庫可能以經有 jar 了,但現在才架好 nexus,那 nexus 肯定沒有這些 jar,所以可以按這個鈕,同步一下

打開 pom 檔,增加如下的設定



<repositories>
    <repository>
        <id>nexus2</id>
        <url>http://localhost:8081/repository/maven-public/</url>
        <releases>
            <enabled>false</enabled>
        </releases>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
    
    <repository>
        <id>central</id>
        <url>http://localhost:8081/repository/maven-central/</url>
    </repository>
</repositories>

※將網址貼到 url 裡。 尤於 url 只能寫一個,所以我寫了兩個 repository 了
如果是第 2 版,因為可以全拉到 group,所以可以只寫一個

※release、snapshots 標籤下的 enabled 標籤表示是否可以下載

※此時隨便找一個目前還沒有的jar,然後下 mvn install,在 console 就能看到從 nexus 下載了

※但如果沒有設定這個東西的人,就不會去 私服下載,所以最好把這個設定放在 settings.xml裡,所以 pom 檔可以刪了,改放在 settings.xml,然後將 settings.xml 複製給要用的人,但要注意設定完不會生效,必需要配置 activeProfile,如下:

<profiles>
    <profile>
        <id>nexus</id>
        <repositories>
            <repository>
                <id>nexus2</id>
                <url>http://localhost:8081/repository/maven-public/</url>
                <releases>
                    <enabled>false</enabled>
                </releases>
                <snapshots>
                    <enabled>false</enabled>
                </snapshots>
            </repository>
    
            <repository>
                <id>central</id>
                <url>http://localhost:8081/repository/maven-central/</url>
            </repository>
        </repositories>
    </profile>
</profiles>
    
<activeProfiles>
    <activeProfile>nexus</activeProfile>
</activeProfiles>


※上面提供的 nexus 連結的 Part2 就幫我們設定好了,只要我們把 copy 的網址貼進去就行
裡面分成三個大 element
profiles:將 pom 檔裡的設定改成放在這,但不會生效
activeProfiles:必需配置這裡的設定才會將 profiles 對應的 id 生效
mirrors:如果不配置,私服關閉了,還是可以去 maven central 下載,可在 settings.xml 加設定,如下:
<mirrors>
    <mirror>
        <id>nexus</id>
        <mirrorOf>*</mirrorOf>
        <url>http://localhost:8081/repository/maven-central/</url>
    </mirror>
</mirrors>

※預設其中有一個 id 為 central 的,在 下載好的maven\lib\maven-model-builder-3.5.2.jar 的 org\apache\maven\model\pom-4.0.0.xml ,他預設 snapshot 的 enable 是 false,可在這裡覆寫

※如果要將自己寫的檔案發佈到私服還得在父 pom 檔裡設定  distributionManagement,這樣子之後就可以用 mvn deploy 發佈到私服,但是會出現「Error code 401, Unauthorized」,如下:

<distributionManagement>
    <repository>
        <id>dmRelease</id>
        <url>http://localhost:8081/repository/maven-releases/</url>
    </repository>
    
    <snapshotRepository>
        <id>dmSnapshot</id>
        <url>http://localhost:8081/repository/maven-snapshots/</url>
    </snapshotRepository>
</distributionManagement>



因為沒有帳號密碼,所以還得在 settings.xml 設定 servers element,裡面的 id要對要到 distributionManagement 裡的 repository 的 id,這要才能發佈到私服
<servers>
    <server>
        <id>dmRelease</id>
        <username>admin</username>
        <password>admin123</password>
    </server>
    
    <server>
        <id>dmSnapshot</id>
        <username>admin</username>
        <password>admin123</password>
    </server>
</servers>

※可以來這個路徑確認一下有沒有 deploy 成功,看你是releases 還 snapshots

※也可以用 Search >> Maven 搜尋

2017年11月4日 星期六

排序:冒泡、選擇、插入


※冒泡排序


元素會像泡泡一樣,往左或往右移動,取決於使用升序或降序,做法是判斷相鄰的元素

綠排為 index,藍排為值
以升序為例,先判斷 index 0和1,然後 index 1和2,一直到最後
每判斷一次,如果左值 > 右值就交換
內迴圈跑完就會產生最大的數在後面,所以內迴圈跑完就會少一次外迴圈



int count = 0;
int[] intArray = new int[] { 5, 4, 3, 2, 1 };
int len = intArray.length - 1;
    
for (int i = 0; i < len; i++) {
    boolean finish = true;
    for (int j = 0; j < len - i; j++) {
        count++;
        if (intArray[j] > intArray[j + 1]) {
            int temp = intArray[j];
            intArray[j] = intArray[j + 1];
            intArray[j + 1] = temp;
            finish = false;
        }
    }
    if (finish) break;
} System.out.println("迴圈跑幾次=" + count); System.out.println(Arrays.toString(intArray));

※外迴圈只有控制內迴圈跑完一次減少一次

※如果要排序的值有一些已經排好順序了,那 finish 變數就會看出效果


※選擇排序

選擇、插入 都是將資料分成已排序和未排序兩個部分
從未排序的元素選擇一個最大或最小值放入排序的元素裡,和插入排序相反

以最上面的圖為例
以升序為例,以 index 0為基底,判斷 index 1、index2…到最後
每判斷一次,如果左值 > 右值就交換
內迴圈跑完就會產生最小的數在前面,所以內迴圈跑完就會少一次外迴圈


int count = 0;
int[] intArray = new int[] { 5, 4, 3, 2, 1 };
int len = intArray.length - 1;
    
for (int i = 0; i < len; i++) {
    boolean finish = true;
    for (int j = 0; j < len - i; j++) {
        count++;
        if (intArray[i] > intArray[j + 1 + i]) {
            int temp = intArray[i];
            intArray[i] = intArray[j + 1 + i];
            intArray[j + 1 + i] = temp;
            finish = false;
        }
    }
    if (finish) break;
} System.out.println("迴圈跑幾次=" + count); System.out.println(Arrays.toString(intArray));

※和冒泡排序只差在 if 而已

※外迴圈是抓基底的來判斷


※插入排序

從未排序的元素第一個插入到排序的元素裡,和選擇排序相反

以最上面的圖為例
以升序為例:
第一次判斷 index 0和1
第二次判斷 index 1和2,再判斷 index 0和1
第三次判斷 index 2和3,再判斷 index 1和2,再判斷 index 0和1
依此類推...
每判斷一次,如果左值 > 右值就交換



int count = 0;
int[] intArray = new int[] { 3, 9, 4, 6, 1, 7, 2, 5, 8 };
    
for (int i = 0; i < intArray.length - 1; i++) {
    for (int j = i; j >= 0; j--) {
        boolean finish = true;
        count++;
        if (intArray[j] > intArray[j + 1]) {             int temp = intArray[j];             intArray[j] = intArray[j + 1];             intArray[j + 1] = temp;             finish = false;         }
        if (finish) break;
    }
}
System.out.println("迴圈跑幾次=" + count);
System.out.println(Arrays.toString(intArray));

※外迴圈 i 值給內迴圈 j