顯示具有 BASH 標籤的文章。 顯示所有文章
顯示具有 BASH 標籤的文章。 顯示所有文章

2011年10月24日 星期一

JDK7 on non-RPM based Linux

JDK 7出來已經有一段時日了,官方網頁也貼心的提供了rpm的套件可以直接安裝,只可惜沒有deb可以下載。雖然如此,我們還是可以省略掉一些手法來同時使用系統提供的jdk6以及網路下載的jdk7--利用update-alternatives工具來達成。但是為了方便作說明,還是先安裝系統套件庫所提供的jdk6吧:

aptitude install sun-java6-jdk

下載適合自己的版本 x86或是x86_64之後,查看自己的java版本以及安裝在何處:

ls -l `which java`
發現原來是連結到/etc/alternatives裡:
lrwxrwxrwx 1 root root 22 2011-10-24 21:39 /usr/bin/java -> /etc/alternatives/java
利用update-alternatives來幫助我們作版本控制,使我們不用手動設定變數等複雜設定,也統一了管理介面。
ls -l /etc/alternatives/java
lrwxrwxrwx 1 root root 36 2011-10-24 21:39 /etc/alternatives/java -> /usr/lib/jvm/java-6-sun/jre/bin/java
所以結果揭曉:/usr/bin/java是來自於/etc/alternatives的一個軟連結,而這個軟連結源自於真正的java位置。所以我們看看他的狀態:
update-alternatives --display java
輸出結果可能會是:
java - auto mode
  link currently points to /usr/lib/jvm/java-6-sun/jre/bin/java
/usr/lib/jvm/java-6-sun/jre/bin/java - priority 63
  slave java.1.gz: /usr/lib/jvm/java-6-sun/jre/man/man1/java.1.gz
Current 'best' version is '/usr/lib/jvm/java-6-sun/jre/bin/java'.

所以我們也可以如法泡製,把下載來的jdk7放在/usr/lib/jvm底下。 請至oracle網站下載最新版本的jdk,假設是jdk-7u25-linux-x64.tar.gz

sudo tar zxvf jdk-7u25-linux-x64.tar.gz -C /usr/lib/jvm/
但此時update-alternatives的cache裡並不會自己發現有jdk的存在,這是安裝一個deb檔的postinst程序才會執行的部份。我們自己試著新增一個,語法如下:
update-alternatives --install <link> <name> <path> <priority>

通常priority大於1000比較有可能是首選。假設您下載了多個jdk7的版本且想要安裝到最新,可以利用下列script來達成:

所以到此為止雖然我們都沒有透過dpkg或是aptitude來安裝jdk7,但是一樣可以作到版本控制,非常方便。

啟動Java plugins:
你可以點我有Java嗎?來測試Java plugin是否有安裝上去。在我的LinuxMint 11 amd64的版本裡,我即使安裝了sun-java6-plugin,無論是我的firefox 或是chrome都無法顯示成功啟動java plugin。
試試看這樣行不行得通:

cd /usr/lib/mozilla/plugins
ln -s /usr/lib/jvm/jdk1.7.0_25/jre/lib/amd64/libnpjp2.so .
如果是rpm-based linux,可以這麼做:
cd /usr/lib/mozilla/plugins
ln -s /usr/java/default/jre/lib/amd64/libnpjp2.so .

參考文章:
man update-alternatives

Share

2011年5月29日 星期日

change vdi UUID

如果你想改變vbox裡某個vdi的uuid檔,你會發現vbox會出現uuid衝突而無法直接使用,這種情形最常發生在更改了vdi檔名然後想重新安裝os。在google上找更改uuid的方法,其參數似乎已經不適用,4.0.x以上的版本應該改用sethduuid參數而不是舊的setvdiuuid。

我寫了一個shell script方便自己更改vdi的uuid:

  1. #!/bin/bash
  2. #############################################################
  3. # Filename: changeVDIuuid.sh
  4. # Date: 2011/05/29
  5. # Purpose: change uuid of vdi file
  6. # Usage:
  7. #
  8. # Description:
  9. # Author: maxsolar(Jim T. Tang@IES, Academia Sinica)
  10. #############################################################
  11.  
  12. ###########################
  13. ## pre-defined variables
  14. ###########################
  15. [ "$1" == "" ] && {
  16.     ls *vdi
  17.     read -p "please specify a vdi file: " vdi
  18.     [ -e "$vdi" ] && {
  19.         VBoxManage internalcommands sethduuid $vdi
  20.     } || {
  21.         echo "$vdi doesn't exist. program terminated."
  22.     }
  23. } || {
  24.     [ -e "$1" ] && {
  25.         VBoxManage internalcommands sethduuid $1
  26.     } || {
  27.         echo "$1 doesn't exist. program terminated."
  28.     }
  29. }

2011年2月21日 星期一

GNOME動態桌布 (Wallpaper Slideshow)

上上禮拜重灌了我的Macbook Pro,也順便重灌了ubuntu 10.10。來澳洲很久沒有動腦筋寫程式了,我想寫寫簡單的shell script或許能提神醒腦一下;剛好email收到台南二寮的一些美麗照片,gnome從2.28以後(好像??)就可以動態變更桌布啦,只是他會去讀取某一個.xml檔。所以理論上就是準備好圖片,準備好讓gnome讀取的xml就搞定了。

雖然網路上已經有許多同好也寫了一些script或是程式,不過總覺得沒有自己寫來來得爽快。我的這隻程式功能非常簡單,就是只會在當前工作目錄找所有的jpg以及png檔,然後在當前目錄下建立一個xml,這個xml可以放置在任何地方,唯有圖片本身路徑不能任意移動(這好像是廢話@_@)。

  1. #!/bin/bash
  2. #############################################################
  3. # Filename: makeGnomeBackground.sh
  4. # Date: 2011/02/20
  5. # Purpose: changing background dynamically
  6. # Usage:
  7. #
  8. # Description:
  9. # Author: maxsolar(Jim T. Tang@IES, Academia Sinica)
  10. #############################################################
  11.  
  12. ###########################
  13. ## pre-defined variables
  14. ###########################
  15. # check if there are jpg or png files in current working dir.
  16. find `pwd -P` -maxdepth 1 -name "*jpg" -o -name "*JPG" > filelist.txt 2>/dev/null
  17. find `pwd -P` -maxdepth 1 -name "*png" -o -name "*PNG" >> filelist.txt 2>/dev/null
  18. [ $(cat filelist.txt | wc -l) -eq 0 ]  && {
  19.     echo "****************************************"
  20.     echo "No .jpg nor .png files found. Try other dirs. "
  21.     echo "****************************************"
  22.     exit 1;
  23. } || {
  24.     cat filelist.txt
  25.     echo "-------------------------------"
  26.     echo "$(cat filelist.txt | wc -l) Pictures were found."
  27. }
  28. year=$(date +"%Y" )
  29. month=$(date +"%m")
  30. day=$(date +"%d")
  31. output=$(basename "`pwd`" /).xml
  32.  
  33. ##main method
  34. read -p "Duration time between pictures?  (default=5) " duration1
  35. [ -z $duration1 ] && {
  36.     duration1=5
  37. }
  38.  
  39. read -p "Duration time within a picture?  (default=600) " duration2
  40. [ -z $duration2 ] && {
  41.     duration2=600
  42. }
  43.  
  44. ## part 1
  45. cat <<HERE > $output
  46. <background>
  47.   <starttime>
  48.     <year>$year</year>
  49.     <month>$month</month>
  50.     <day>$day</day>
  51.     <hour>00</hour>
  52.     <minute>00</minute>
  53.     <second>00</second>
  54.   </starttime>
  55. <!-- This animation will start at midnight. -->
  56. HERE
  57. ## part 2
  58. declare -a picArray=(`cat filelist.txt`)
  59. declare -i loops=$(cat filelist.txt | wc -l)
  60. for (( i=1; i<="$loops"; i++ )) ; do
  61.     ##The Last Loop
  62.     if [ $i -eq $loops ]; then 
  63.         cat <<HERE >>$output
  64.   <static>
  65.     <duration>$duration2</duration>
  66.     <file>${picArray[$i-1]}</file>
  67.   </static>
  68.   <transition>
  69.     <duration>$duration1</duration>
  70.     <from>${picArray[$i-1]}</from>
  71.     <to>${picArray[0]}</to>
  72.   </transition>
  73. HERE
  74.     else
  75.     ## in formal loops
  76.         cat << HERE >>$output
  77.  <static>
  78.     <duration>$duration2</duration>
  79.     <file>${picArray[$i-1]}</file>
  80.   </static>
  81.   <transition>
  82.     <duration>$duration1</duration>
  83.     <from>${picArray[$i-1]}</from>
  84.     <to>${picArray[$i]}</to>
  85.   </transition>
  86. HERE
  87.     fi
  88. done
  89. echo "</background>" >> $output
  90.  
  91. echo \"$output\" is made.
  92.  
  93. ## remove temparary file
  94. rm filelist.txt

這個script會讀取當前目錄下的所有jpg/png檔(不分大小寫),然後提問:
1.圖片間切換時間,直接按下enter預設5秒;
2.每張圖片的時間,直接按下enter預設600秒。輸出的xml檔名預設就是該目錄的名稱,建立成功會有提示出現。

在桌面空白處按右鍵->Change Desktop Background->Add

切換到想要gnome讀取的那個資料夾之後,選擇All Files,就可以看到該xml檔。

選取剛剛做好的xml檔之後,就可以在桌布預覽的地方看到我們剛剛的作品。

網路上也有幾篇好玩的可以看看:
Create Your Own GNOME Background Slideshow
[分享] Gnome動態桌布
自動換桌布的shell script

2010年4月9日 星期五

批次修改圖片大小-convert

最近在BBS上看到有網友詢問如何利用convert指令做批次轉換。在先前的批次修改圖片大小裡有提到一些方法。不過當時我一直忘記把script寫上來,今天特地補上。

#!/bin/bash

for files in *.ps; do
    name=$(echo $files | cut -d. -f1).pdf
    convert $files $name
done

這個作法的好處就是只要修改.ps跟.pdf這兩個關鍵字即可。當然他不是一個完美script-- 你還可以讓他變得更人性:

#!/bin/bash
## Author: Jim T. Tang (http://maxubuntu.blogspot.com)
if [ -z $1 -a -z $2 ]; then
    echo "usage: $0 jpg png";
    exit 0;
elif [ -z $2 ]; then
    echo "need target format. e.g. ps"
else
    for files in *.$1 ; do
        name=$(echo $files | cut -d. -f1).$2
        convert $files $name
        echo "$name is made."
    done
fi 

2010年1月19日 星期二

Here Document與Java程式的搭配使用

這幾天一直百思不得其解,從前利用Here Document來傳值給C++/Fortran程式都能夠輕易完成;昨天寫了一個小小的轉換格式的程式想搭配shell script完成任務卻出現了NoSuchElementException 的尷尬問題,怎麼嘗試都不成功。

所謂Here Document,意思就是在子process裡傳入參數。在父process還在運行的時候,預先把參數值寫好,等到運行到子process的時候,不必等待使用者提示即可傳值。舉個例子:

假設someprog是一個C++/Fortran程式,過程中會提示,輸入兩個字串兩個數值:

#!/bin/sh
/usr/local/bin/someprog << END
vespa.env.out
vespa.ent.OUT
23.5
2.0
END

這種在script裡就先把要傳入的參數先寫好的方法,便是常被使用的Here Document。然而,今天我也寫了一個落落長的java互動式程式,卻拋出了NoSuchElementException 的例外。為了檢查到底是哪裡出問題,我寫了一個更簡單的程式來代替:

假設這個程式稱為TestString:

import java.util.*;

public class TestString{
  public static void main(String[] args){
    System.out.println("1st enter:");
    String tmpstr = new Scanner(System.in).nextLine();

    System.out.println("1st enter is "+tmpstr+". Now enter 2nd :");
    tmpstr = new Scanner(System.in).nextLine();

    System.out.println("2nd enter is "+tmpstr);
 }
}

編譯他並包成jar檔:
jar -cmvf menifest.mf TestString.class
當然,你的menifest.mf在預設套件的情況下可能會長這樣:
Main-Class: TestString

由於java程式是byte-code而非native-code,因此需要jvm去驗證並啟動他;想要模擬C++程式直接呼叫binary這樣的方法,只需要一個小小的script來解決:首先建立一個跟java程式同檔名的文字檔,以此例即為TestString,其內容如下:

#!/bin/bash
#Program TestString
[ -e `which java` ] && java -jar /home/maxsolar/bin/TestString.jar

exit 0;

當然別忘記把這個script加上可執行屬性,並放在你的PATH範圍裡。
執行以下的script來試試看!

#!/bin/bash
TestString << END
string1
string2
END

結果卻出現了下列錯誤訊息:
1st enter:
1st enter is string1. Now enter 2nd :
Exception in thread "main" java.util.NoSuchElementException: No line found
    at java.util.Scanner.nextLine(Scanner.java:1516)
    at TestString.main(TestString.java: 9)

對還不太能掌握java的我,實在不清楚究竟是為了麼值會傳不進去。困擾我一整天之後,決定到台灣最大的JavaWorld@TW論壇去爬文,卻沒有跟我的情況有類似的問題。後來在版上發問,沒想到很快的就有高手來解決我的問題:

Scanner 在某些操作上會有 buffering 的行為,如果要透過 Scanner 來處理 standard input 裡的數據,應只使用一個 Scanner instance。

import java.util.*;
public class TestString {

    public static void main(String[] args) {
        System.out.println("1st enter:");
        final Scanner scanner = new Scanner(System.in);
        String tmpstr = scanner.nextLine();

        System.out.println("1st enter is " + tmpstr + ". Now enter 2nd :");
        tmpstr = scanner.nextLine();

        System.out.println("2nd enter is " + tmpstr);
    }
}

如此一來,我使用的Scanner物件將會是唯一。先前我所使用的是anonymous的方法產生物件並直接傳到tmpstr這個字串物件接收,但是根據Dunkan前輩的建議,要使用一個唯一的Scanner物件來接收我的標準輸入,才能擺脫被buffered在記憶體的問題。

非常感謝Dunkan前輩精確且迅速的解答,因此把這篇作成筆記,好讓自己跟需要的Java與linux同好可以有機會參考。

參考連結:
[請益]shell script呼叫java程式並傳入值的問題

2009年10月20日 星期二

自動重開機500次?

在bbs的linux版上看到有網友想找可以自動reboot500次的linux程式,我覺得很有趣;不過一下就把script公佈出來,一點趣味也沒有。所以我就先把解答寫在這裡,也許有一天,他會找到這篇。

重開機500次可能是要測試硬體吧,這就超過我的專長;不過自動重開機卻可以用8行不到的script輕鬆解決:

修改/etc/rc.local,新增一行如下:

[ -e /boot/autoReboot.sh ] && bash /boot/autoReboot.sh
然後新增一個/boot/autoReboot.sh內容如下:

所需要會的技巧相當簡單:
1. 會使用while loop。
2. 會使用test敘述。
3. 會使用shell script裡的整數運算(雖然他非常陽春)。
4. 會使用function(雖然他非常陽春)。
5. 知道開機時要額外啟動的命令檔為何。

2009年10月10日 星期六

大小寫互換--進階版

最近用select寫了一個進階版的大小寫互換程式,供各位參考。

2009年10月1日 星期四

變數值代換(variables substitution)精簡筆記

變數值代換相較於指令代換,是一般使用者比較少碰到的;不過當你要成為一位合格的bash/csh programmer,變數值代換可是要跟吃飯喝水一樣自然。

Case 1. ${variable-'defaultValue'}
意義:當variable不存在時,將variable暫時指定成defaultValue。所謂「暫時」,是指此行之後,在整個script裡variable都還是不存在此變數名稱。

結果:

Maxsolar
       <---沒有輸出
可以發現,第一行的Maxsolar是利用變數值替換得來的,但是事實上我們並沒有真的設定myname,因此echo的結果為無。

Case 2. ${variable:-'defaultValue'}
意義:當variable不存在或為空值時,將variable暫時指定成defaultValue。所謂「暫時」,是指此行之後,在整個script裡variable都還是不存在或變數值不改變。

結果:

Maxsolar
       <---空的輸出
可以發現,由於myname存在但為空值,因此暫時被設定成Maxsolar,但隨即變失去了Maxsolar這個值,因此第一行輸出Maxsolar,第二行的輸出為空值(請注意跟case 1的「沒有輸出」看起來一樣,意義卻不相同)。

Case 3. ${variable:='defaultValue'}
意義:表示variable若不存在或為空值,則指定defaultValue給variable。variable將在整個script裡都為defalutValue。
這是最為常見的變數值替換。

結果:

Maxsolar
Maxsolar
可以發現,由於myname是空值,因此利用":="將myname的值永久設定成Maxsolar(所謂永久,指的是在此script的生命週期裡)。因此兩個輸出都會是Maxsolar。
事實上,在我們的終端機裡控制命令列最前面的 使用者名稱@主機名稱:工作路徑 的這個表示法,就是在~/.bashrc裡利用此變數替換方法來達成的:

Case 4. ${variable:?'defaultValue'}
意義:若variable不存在或為空值,則會出現在std err上,以檢查變數值是否被正確設定。
此變數值替代表示法常用在debug,而不會真正用在可執行的script上,遇到錯誤就會直接停止,無法利用std err導向輸出。

結果:

test.sh: line 32: myname: Maxsolar
因為myname被預期設定值為Maxsolar,但是卻是空值,因此會觸發一個標準錯誤輸出,script嘎然而止。

Case 5. ${variable:+'defaultValue'}
意義:表示variable若已被設定,則本行的variable暫時被設定為defalutValue,但整個script裡的variable未被改變。

結果:

maxubuntu
Maxsolar
可以發現:myname非空值,因此將會被暫時設定成maxubuntu;但是myname的值不會因此改變,仍然是Maxsolar。

好險,變數值的替換就這五種類型,多看個兩次就可以完全懂了。

小節:

  1. 只想測試變數是否為空值:
    可以用"-", ":-"來檢查,且指定的值只有一行的生命。
  2. 若某變數沒有值,就賦值給他:
    可以用":="來指定
  3. 想檢查該變數值是否為某值:
    利用":?"來debug囉!!
  4. 想臨時改變某一個有值的變數:
    利用":+"來賦值。
  5. 想永久改變某一個有值的變數:
    婀,你一定忘記變數值是可以被override的!直接將某變數指定值給他就可以啦!別想太複雜囉!

2009年9月22日 星期二

檢查目錄下的檔案或資料夾數目

這個script,可以幫你檢查當前目錄下,有多少目錄、檔案、隱藏檔以及連結檔。

用法:
只要在該目錄下,直接執行此script即可。

2009年2月5日 星期四

大小寫互換

很多人換大小寫會用程式語言來作,不過我覺得殺雞焉用牛刀,恰好也該開始練習shell script了!
#!/bin/bash

read -p "請輸入: 1.大轉小 2.小轉大 3.指定轉換副檔名: " choice

case "$choice" in
1) for file in *
do
  lower=`echo "$file" | tr [:upper:] [:lower:]`
  [ "$file" != "$lower" ] &&
  mv "$file" "$lower"
done
echo "轉換完成!"
ls
exit 0
;;

2) for file in *
do
  upper=`echo "$file" | tr [:lower:] [:upper:]`
  [ "$file" != "$upper" ] &&
  mv "$file" "$upper"
done
echo "轉換完成!"
ls
exit 1
;;

3) echo  "輸入欲轉換副檔名:"
read subname
echo  "輸入轉換後的副檔名:"
read newsubname

for file in *.$subname
   do
       mv "$file" "$(basename $file .$subname).$newsubname"
   done
# basename的語法:
# basename /usr/bin/sort       Output "sort".
# basename include/stdio.h .h  Output "stdio".
echo "轉換完成!"
ls
exit 2
;;
*) echo "請輸入1或2。程式終止!"
;;
esac

exit 3
大家試試看吧@! 事實上,我比較喜歡用rename這個指令。利用rename的話,紅色的那行指令可以改寫成:
rename  's/$subname/$newsubname/'  *.$subanme
不過,我手邊現有的機器只有debian跟opensuse 11.1,雖然兩者都有rename指令,不過rename對於opensuse卻沒有效果,也沒有錯誤訊息。查了一下rename是在util-linux套件裡,我也檢查了opensuse確實有安裝util-linux,但就是無效;因此我才選用紅色的code作為各版本通用的script。 OpenSuSE裡的rename用法,以此情況應該改成如下:
rename ".$subname"  ".$newrename"  *.subname
這實在是很不太妙,我竟然要去考慮不同linux間的相同指令的問題!目前只好用basename的的方法來做了!