shell script for download virtualbox packages

หลังจากบรรยายเรื่อง Shell script ไปในสัปดาห์ที่แล้ว ด้วยหัวข้อเรื่องที่มีอยู่ค่อนข้างเยอะกว่าที่คิดไว้ และใช้เวลาบรรยายไปอย่างไม่ค่อยมีประสิทธิภาพสักเท่าไหร่ ทำให้เนื้อเรื่องบางส่วน ต้องทิ้งเอาไว้ ไม่ได้พูดต่อให้จบ ปล่อยคนที่เอา slide มาอ่านงงไปก็แล้วกันว่า มันคือเรื่องอะไรกัน

เรื่อง slide ก็ … เหอะ … เดี๋ยวมีโอกาส ค่อยกลับไปปรับปรุงมันอีกที ผมยังพอมี idea อยู่บ้างว่าจะแก้ไขมันยังไง แต่เรื่องหนึ่งซึ่งจริงๆแล้ว มีปัญหาตั้งแต่ก่อนเริ่มบรรยายแล้วว่า จะยกตัวอย่างโจทย์ปัญหาอย่างไรดี ที่จะทำให้เห็น วิธีการที่ผมใช้ในการ “เขียน” shell script ตัวนึงออกมาได้ ตัวอย่างที่ยกให้ดูในตอนแรกของ การบรรยาย เป็นแค่ตัวอย่างหลอกๆ ที่เขียนไปเพื่อให้เห็น รูปแบบ ของการใช้ shell script แต่จะว่าไป ที่ผมใช้งานอยู่ปัจจุบัน ก็ไม่ได้ตัวอย่างที่ว่านั่น จะใช้ตัวอย่างอื่นที่มี ตัวอย่างเช่น psuautosigned ก็คงต้องอธิบายในเรื่องอื่นกันยาว ก่อนที่จะวกกลับมาที่เรื่องของ shell script ได้

จนกระทั่งวันนี้ ได้รับ email ฉบับนี้มา

> อาจารย์ครับ
>    มีเรืองปรึกษครับ
>
> สิ่งที่ต้องการคือ wget file หลายๆ  file ตามข้างล่างนี้
> wget
> http://download.virtualbox.org/virtualbox/${version1}/VirtualBox-${version1}-83876-Win.exe
> wget
> http://download.virtualbox.org/virtualbox/${version1}/virtualbox-4.2_${version1}-83877~Ubuntu~quantal_i386.deb
> wget
> http://download.virtualbox.org/virtualbox/${version1}/virtualbox-4.2_${version1}-83876~Ubuntu~quantal_amd64.deb
> wget
> http://download.virtualbox.org/virtualbox/${version1}/virtualbox-4.2_${version1}-83876~Ubuntu~precise_i386.deb
> wget
> http://download.virtualbox.org/virtualbox/${version1}/virtualbox-4.2_${version1}-83876~Ubuntu~precise_amd64.deb
> wget http://download.virtualbox.org/virtualbox/${version1}/MD5SUMS
> wget
> http://download.virtualbox.org/virtualbox/${version1}/Oracle_VM_VirtualBox_Extension_Pack-${version1}-83876.vbox-extpack
> wget http://download.virtualbox.org/virtualbox/${version1}/UserManual.pdf
>
> ผมเขียน  script แบบนี้
> version1=4.2.8
> url1=http://download.virtualbox.org/virtualbox/${version1}
> for i in Win  quantal  precise Oracle MD5 User
>     do
>        wget  ${url1}/*{i}*
>    done
> ไม่ work ครับ
> ขอคำแนะนำด้วยครับ

ผมตอบกลับไปว่า

|        ใช้ *{i}* หรือ *${i}* ไม่ได้ครับ เพราะ * ที่ใช้บน command line
|        ปกติ จะเป็นตัวอักษรที่ตีความโดย shell ที่เราใช้งานอยู่ ซึ่งโดยทั่วไป
|        มันก็จะพยายาม match กับ ชื่อไฟล์ ใน directory บนเครื่องของเราครับ
|
|        ทีนี้ ตอนท่ีส่งให้กับ wget ถ้า shell ไม่สามารถ expand ตัว * ออกมาเป็น
|        ไฟล์ได้ มันก็จะส่ง * ไปยังเครื่องปลายทาง ซึ่งก็จะเปรียบเทียบแบบ literal
|        คือเป็นตัวอักษร * โดยตรงโดยไม่ได้พยายาม match กับไฟล์ที่มีอยู่ใน
|        directory นั้นๆ
|
|        วิธีการหนึ่งที่อาจจะใช้สำหรับการ download ทั้งหมดมาได้ ก็คือใช้ option -r
|        แต่ว่านั่นก็จะได้ไฟล์ ที่เราไม่ต้องการมาอีกหลายๆไฟล์
|
|       สำหรับกรณีนี้ วิธีการที่ สามารถใช้ในการแก้ปัญหาได้ก็คือ อ่าน list ของไฟล์
|       ที่มีอยู๋ทั้งหมดมาก่อน แล้วค่อยมาเลือกชื่อไฟล์ที่เราต้องการ เอามาเก็บไว้ใน
|       list ที่เราต้องการ download อีกรอบนึง ครับ
|
|       อันที่จริงแล้ว นี่เป็นคำถามที่ดีมาที่จะใช้ยกตัวอย่างในเรื่องของการใช้งาน
|       shell script เลยทีเดียวครับ
|
|       ผมกำลังหา หัวข้อเรื่องที่เหมาะสมสำหรับเขียนเป้น blog ลงใน psu sysadmin
|       พอดีเลยครับ ผมขอเอาคำตอบไปตอบในโน้นนะครับ

จริงๆแล้วแอบร้องยูเรก้าอยู่ในใจ เพราะนี่แหละสิ่งที่ผมต้องการ ไม่ต้องรอคำอนุญาตจากเจ้าของ email ผมก็รีบเอามา post ที่นี่ทันทีถ้าไม่มีคำถามดีๆ ผมก็ไม่มีไอเดีย อะไรที่จะเอามาเขียนเป็น blog เหมือนกันครับ ของคุณเจ้าของ email ที่ส่งมาถามเป็นอย่างมากเลยครับขอเริ่มจากอธิบายโจทย์ใหม่อีกสักรอบก่อนนะครับโจทย์ คือต้องการที่จะ download package ของ virtualbox ใหม่ล่าสุดที่มีอยู่บน site ของ virtualbox มาเก็บไว้ที่ local เพื่อให้การติดตั้ง package บนเครื่องคอมพิวเตอร์ในเครือข่าย ซึ่งมีอยู่หลายเครื่อง จะได้ไม่ต้องไป download มาสำหรับแต่ละเครื่องให้เปลือง bandwidthถ้าหากว่า เครื่องคอมพิวเตอร์ที่ใช้ เป็น Linux และติดตั้ง Ubuntu Linux หรือ Debian Linux และต้องการ
VirtualBox ตัวที่ทันสมัย แต่ไม่ถึงกับต้องการตัว “ล่าสุด” จริงๆ ปัญหานี้ก็สามารถแก้ได้ง่ายๆ โดยติดตั้ง
Virtualbox บนเครื่อง โดยการใช้คำสั่ง

sudo apt-get install virtualbox

ซึ่งบนเครื่อง Debian Wheezy ที่ผมใช้งานอยู่ปัจจุบัน ก็จะมี Virtualbox 4.1.8 ให้ใช้ติดตั้งได้เลย โดยไม่ต้อง download มาจาก website ของ virtualbox

แต่ถ้าต้องการ virtualbox version ล่าสุด ซึ่ง version stable ล่าสุด ซึ่งประกาศ release อยู่บน website ของ virtualbox (ณ วันนี้ 6 มีค. 2556) คือ 4.2.8 ซึ่งก็ … อะ แฮ่ม … ต่างกันไม่มากเท่าไหร่

แต่ถ้าต้องการ version ล่าสุด หรือ package สำหรับ Windows หรือ Mac OSX ด้ว ก็คงต้องใช้วิธีการ download มาจาก website ของ virtualbox โดยตรงจาก https://www.virtualbox.org/wiki/Downloads ครับ

กลับมาที่ โจทย์ ต่อ

เราต้องการ download package ของ virtualbox ตัวล่าสุด และต้องการไฟล์ package สำหรับ
1. Windows
2. Ubuntu โดยแยกเป็น
2.1 Ubuntu 12.04 — precise pangolin
2.2 Ubuntu 12.10 — quantal quetzal
ทั้งสอง revision ต้องการ package สำหรับทั้ง i386 และ amd64 architecture
3. Extension pack
4. User manual
5. ไฟล์ MD5SUMS สำหรับตรวจสอบไฟล์ ที่ download มา

ไฟล์ของ virtualbox ซึ่งสร้างเป็น link ไว้ ในหน้า download จะเก็บอยู่บน http://download.virtualbox.org/virtualbox/4.2.8/ สำหรับ version 4.2.8

ซึ่งถ้าเรา list มาดูจะได้ ประมาณนี้

[DIR]  Parent Directory
[   ]  MD5SUMS                                                          01-Mar-2013 02:11     3K    
[   ]  Oracle_VM_VirtualBox_Extension_Pack-4.2.8-83876.vbox-extpack     27-Feb-2013 12:56    10M    
[   ]  Oracle_VM_VirtualBox_Extension_Pack-4.2.8.vbox-extpack           27-Feb-2013 12:56    10M    
[   ]  SDKRef.pdf                                                       27-Feb-2013 12:55     2M    
[   ]  SHA256SUMS                                                       01-Mar-2013 02:12     5K    
[   ]  UserManual.pdf                                                   27-Feb-2013 12:55     5M    
[BIN]  VBoxGuestAdditions_4.2.8.iso                                     27-Feb-2013 13:00    54M    
[   ]  VirtualBox-4.2-4.2.8_83876_el4-1.i386.rpm                        27-Feb-2013 12:45    82M    
[   ]  VirtualBox-4.2-4.2.8_83876_el5-1.i386.rpm                        27-Feb-2013 12:45    81M    
[   ]  VirtualBox-4.2-4.2.8_83876_el5-1.x86_64.rpm                      27-Feb-2013 13:01    81M    
[   ]  VirtualBox-4.2-4.2.8_83876_el6-1.i686.rpm                        27-Feb-2013 12:45    67M    
[   ]  VirtualBox-4.2-4.2.8_83876_el6-1.x86_64.rpm                      27-Feb-2013 13:01    67M    
[   ]  VirtualBox-4.2-4.2.8_83876_fedora16-1.i686.rpm                   27-Feb-2013 12:45    66M    
[   ]  VirtualBox-4.2-4.2.8_83876_fedora16-1.x86_64.rpm                 27-Feb-2013 12:45    66M    
[   ]  VirtualBox-4.2-4.2.8_83876_fedora17-1.i686.rpm                   27-Feb-2013 12:45    66M    
[   ]  VirtualBox-4.2-4.2.8_83876_fedora17-1.x86_64.rpm                 27-Feb-2013 12:45    66M    
[   ]  VirtualBox-4.2-4.2.8_83876_fedora18-1.i686.rpm                   27-Feb-2013 12:46    68M    
[   ]  VirtualBox-4.2-4.2.8_83876_fedora18-1.x86_64.rpm                 27-Feb-2013 12:46    68M    
[   ]  VirtualBox-4.2-4.2.8_83876_mdv2010.0-1.i586.rpm                  27-Feb-2013 12:46    69M    
[   ]  VirtualBox-4.2-4.2.8_83876_mdv2010.0-1.x86_64.rpm                27-Feb-2013 12:46    69M    
[   ]  VirtualBox-4.2-4.2.8_83876_mdv2011.0-1.i586.rpm                  27-Feb-2013 12:46    61M    
[   ]  VirtualBox-4.2-4.2.8_83876_mdv2011.0-1.x86_64.rpm                27-Feb-2013 12:46    61M    
[   ]  VirtualBox-4.2-4.2.8_83876_openSUSE114-1.i586.rpm                27-Feb-2013 12:46    61M    
[   ]  VirtualBox-4.2-4.2.8_83876_openSUSE114-1.x86_64.rpm              27-Feb-2013 12:46    61M    
[   ]  VirtualBox-4.2-4.2.8_83876_sles10.1-1.i586.rpm                   27-Feb-2013 12:46    80M    
[   ]  VirtualBox-4.2-4.2.8_83876_sles10.1-1.x86_64.rpm                 27-Feb-2013 12:46    80M    
[   ]  VirtualBox-4.2-4.2.8_83876_sles11.0-1.i586.rpm                   27-Feb-2013 12:46    73M    
[   ]  VirtualBox-4.2-4.2.8_83876_sles11.0-1.x86_64.rpm                 27-Feb-2013 12:47    73M    
[BIN]  VirtualBox-4.2.8-83876-Linux_amd64.run                           27-Feb-2013 12:55    79M    
[BIN]  VirtualBox-4.2.8-83876-Linux_x86.run                             27-Feb-2013 12:55    79M    
[   ]  VirtualBox-4.2.8-83876-OSX.dmg                                   27-Feb-2013 12:55   103M    
[   ]  VirtualBox-4.2.8-83876-SunOS.tar.gz                              27-Feb-2013 12:55   113M    
[BIN]  VirtualBox-4.2.8-83876-Win.exe                                   27-Feb-2013 12:55    93M    
[   ]  VirtualBox-4.2.8.tar.bz2                                         28-Feb-2013 02:22    72M    
[   ]  VirtualBoxSDK-4.2.8-83876.zip                                    27-Feb-2013 13:00     9M    
[   ]  virtualbox-4.2_4.2.8-83876~Debian~squeeze_amd64.deb              27-Feb-2013 09:00    60M    
[   ]  virtualbox-4.2_4.2.8-83876~Debian~squeeze_i386.deb               27-Feb-2013 08:49    60M    
[   ]  virtualbox-4.2_4.2.8-83876~Debian~wheezy_amd64.deb               27-Feb-2013 10:20    60M    
[   ]  virtualbox-4.2_4.2.8-83876~Debian~wheezy_i386.deb                27-Feb-2013 10:05    61M    
[   ]  virtualbox-4.2_4.2.8-83876~Ubuntu~hardy_amd64.deb                27-Feb-2013 12:12    82M    
[   ]  virtualbox-4.2_4.2.8-83876~Ubuntu~hardy_i386.deb                 27-Feb-2013 11:59    79M    
[   ]  virtualbox-4.2_4.2.8-83876~Ubuntu~lucid_amd64.deb                27-Feb-2013 09:42    71M    
[   ]  virtualbox-4.2_4.2.8-83876~Ubuntu~lucid_i386.deb                 27-Feb-2013 09:33    71M    
[   ]  virtualbox-4.2_4.2.8-83876~Ubuntu~natty_amd64.deb                27-Feb-2013 08:38    59M    
[   ]  virtualbox-4.2_4.2.8-83876~Ubuntu~natty_i386.deb                 27-Feb-2013 08:26    59M    
[   ]  virtualbox-4.2_4.2.8-83876~Ubuntu~oneiric_amd64.deb              27-Feb-2013 11:46    59M    
[   ]  virtualbox-4.2_4.2.8-83876~Ubuntu~oneiric_i386.deb               27-Feb-2013 11:30    60M    
[   ]  virtualbox-4.2_4.2.8-83876~Ubuntu~precise_amd64.deb              27-Feb-2013 09:24    60M    
[   ]  virtualbox-4.2_4.2.8-83876~Ubuntu~precise_i386.deb               27-Feb-2013 09:10    60M    
[   ]  virtualbox-4.2_4.2.8-83876~Ubuntu~quantal_amd64.deb              27-Feb-2013 08:56    59M    
[   ]  virtualbox-4.2_4.2.8-83877~Ubuntu~quantal_i386.deb               01-Mar-2013 01:45    60M

ถ้าต้องการ download มาทั้งหมด ก็ทำได้โดยการใช้คำสั่ง

 wget -r -np -nH --cut-dirs=2 http://download.virtualbox.org/virtualbox/4.2.8/

แต่ก็จะเห็นว่าเราจะได้ไฟล์จำนวนมากที่เราไม่ต้องการมาด้วย เราต้องการไฟล์จริงๆเพียงไม่กี่ไฟล์ เพราะฉะนั้น ก็ต้องทำงานเพ่ิมขึ้นอีกหน่อยนึง

แต่ก่อนที่จะเริ่ม จากการ download ไฟล์จาก directory ที่เราต้องการ ซึ่งเรารู้ตำแหน่งที่แน่นอนอยู่แล้ว จากการสำรวจแบบ manual มาตั้งข้อสมมติฐานก่อนว่า ถ้าเมื่อไหร่ virtualbox มีการ release version ใหม่ออกมา เราก็ควรที่จะรู้ได้โดยอัตโนมัติ หรืออย่างน้อย เราก็ไม่น่าจะจำเป็นที่จะต้องมาเขียน script ใหม่ … คำถามคือ เราจะรู้ได้ใหม? และ ถ้าได้ เราจะรู้ได้อย่างไร

คำตอบแรกคือ ได้ คำตอบถัดมามี อยู่หลายทางเลือกครับ แต่ถ้าเอาแบบไม่ซับซ้อนมากนัก วิธีการที่ผมใช้แบบ manual อยู่ก็คือ เข้าไปดูที่ https://www.virtualbox.org/wiki/Downloads ซึ่งในหน้าที่ก็จะ list ตัว package ของ virtualbox ที่จะให้ download สำหรับ OS ต่างๆ และจะมี ระบุ version เอาไว้ด้วย

ในบรรทัดที่ใช้สำหรับระบุ URL ให้ download ของ Linux ก็จะเขียนไว้ว่า

VirtualBox 4.2.8 for Linux hosts

ตัวเลข 4.2.8 คือ version ซึ่งจะเปลี่ยนไปเรื่อยๆ เมื่อ Virtualbox มีการ update เป็น version ใหม่
เราสามารถ เอาตัวเลขนี้ มาได้ โดยการใช้ความร่วมมือระหว่าง โปรแกรม 2 ตัว คือ wget กับ grep โดยที่คำสั่ง

wget -q -O- http://www.virtualbox.org/wiki/Downloads

เราจะได้ ข้อมูลของ page ดังกล่าวอยู่ในรูป html ปรากฏขึ้นบนหน้าจอ … เราต้องการเฉพาะบรรทัดที่ระบุ URL สำหรับ Linux ก็สามารถใช้ grep สำหรับ ตัดมา เฉพาะบรรทัดนั้นได้ โดยการใช้คำสั่ง

wget -q -O- http://www.virtualbox.org/wiki/Downloads | grep 'for Linux hosts'

ซึ่งจะได้ผลลัพธ์ออกมาเป็น

</li><li><strong><a href="/wiki/Linux_Downloads">VirtualBox 4.2.8 for Linux hosts</a></strong>

และ โดยการใช้คำสั่ง sed เพื่อที่จะตัดข้อความข้างหน้า ตั้งแต่ <li><s… ไปจนถึง VirtualBox ทิ้งไป ก็สามารถเพิ่มคำสั่งเข้าไปเป็น

wget -q -O- http://www.virtualbox.org/wiki/Downloads  |\
grep 'for Linux hosts' |\
sed -e 's/^.*VirtualBox //'

ก็จะได้ผลลัพธ์ออกมาเป็น

4.2.8 for Linux hosts</a></strong>

คราวนี้ เพิ่มส่วนของการกำจัดข้อความด้านหลังตัวเลข version โดยใช้ expression ที่สองของ sed ก็จะได้คำสั่งเป็น

wget -q -O- http://www.virtualbox.org/wiki/Downloads  |\
 grep 'for Linux hosts' |\
 sed -e 's/^.*VirtualBox //' -e 's/ for Linux hosts.*$//'

และได้ผลลัพธ์ออกมาเป็น

4.2.8

สวยงามไม่มีที่ติ Smile
เอาน่า … เชื่อผมหน่อยน่า บอกว่าสวยก็สวยสิ!

หลังจากพยายามมาสักพักเราก็ได้ตัวเลข version มา … ซึ่งจะเสียเวลากับมันมากไปหรือเปล่า? …
เอาน่า โดยตัวเลขที่มีอยู่นี้ เราสามารถเขียน script สำหรับการตรวจสอบว่า Virtualbox มีการ update version ใหม่หรือเปล่า โดยการเอา code ข้างต้น มาปรับให้เป็น script ได้ประมาณนี้

#!/bin/sh

VBOXWIKIDL="http://www.virtualbox.org/wiki/Downloads"

getVBoxVersion() {
    VERS=`wget -q -O- $VBOXWIKIDL          |\
          grep 'for Linux hosts'           |\
          sed  -e 's/^.*VirtualBox //'      \
               -e 's/ for Linux hosts.*$//' `
}

getVBoxVersion
echo "Last VirtaulBox Version = $VERS"

เขียนส่วนของ code ให้ execute ใน backtick เพื่อส่งค่ามาให้กับตัวแปร shell VERS ซึ่งเราจะเอาไปใช้ต่อไป ใช้ตัวแปร VBOXWIKIDL สำหรับการระบุ URL ของ download page เพื่อให้ code อ่านง่ายขึ้น และเขียนในรูปแบบของ shell function เพื่อที่เราจะเอาฟังก์ชันนี้ไปใช้ในงานอื่นต่อไปในอนาคต

กำหนด ชื่อให้ script เป็น vboxvers แล้วกำหนดให้มัน execute ได้โดยการใช้คำสั่ง

chmod +x vboxvers

และทดสอบ

./vboxvers

เราก็จะได้ script สำหรับแสดง version ล่าสุดของ VirtualBox ที่มีให้ download จาก website ของ VirtualBox … แต่ถ้าให้ดีขึ้นไปกว่านี้ ตัว script นี้ควรจะทำงานโดยอัตโนมัติ โดยการตรวจสอบวันละครั้ง และถ้ามี version ที่ใหม่กว่า ก็ค่อยส่ง email มาแจ้งเรา

ซึ่งเราสามารถทำได้โดย การเพิ่ม code สำหรับการเก็บข้อมูล version ล่าสุดที่เคยตรวจสอบเอาไว้ในไฟล์ และเปรียบเทียบ ตัวเลขนั้นกับ version ใหม่ที่มี สมมติให้ไฟล์นั้นชื่อ .vboxvers.txt เก็บไว้ใน HOME ของเราเอง

FILE="$HOME/.vboxvers.txt"

ถ้ามีไฟล์นั้นอยู่ เราก็อ่านค่า version ล่าสุดที่เคยตรวจสอบมาจากไฟล์นั้น แต่ถ้าไม่มีไฟล์ ก็กำหนดค่า version เริ่มต้นให้เป็น “0.0.0” ซะ

if [ ! -f "$FILE" ]; then
        LAST="0.0.0"
else
        LAST=`cat $FILE`
fi

หลังจากนั้น เราก็จะอ่านค่า version ล่าสุดจาก web ของ VirtualBox มาโดยใช้ ฟังก์ชัน getVBoxVersion ที่เขียนเอาไว้แล้ว

เอาค่าที่ได้มาเปรียบเทียบกัน ถ้าไม่เท่ากัน ก็ส่ง email ให้กับ address ที่กำหนดเอาไว้

if [ "$LAST" != "$VERS" ]; then
        echo "New VirtualBox $VERS available" |\
        mail -s "VirtualBox $VERS" $EMAIL
        # Save new version
        echo "$VERS" > $FILE
fi

ซึ่งก็จะได้ script สุดท้ายมีหน้าตาประมาณนี้ครับ

#!/bin/sh

VBOXWIKIDL="http://www.virtualbox.org/wiki/Downloads"
FILE="$HOME/.vboxvers.txt"
EMAIL="me@example.com" # Change to your email address!

getVBoxVersion() {
    VERS=`wget -q -O- $VBOXWIKIDL          |\
          grep 'for Linux hosts'           |\
          sed  -e 's/^.*VirtualBox //'      \
               -e 's/ for Linux hosts.*$//' `
}

# Check whether we have version file
# if not use initial 0.0.0 version
# if there is, then get the last version from that file
if [ ! -f "$FILE" ]; then
        LAST="0.0.0"
else
        LAST=`cat $FILE`
fi

# Then get lastest version from VirtualBox web
getVBoxVersion

# Then check and report
if [ "$LAST" != "$VERS" ]; then
        echo "New VirtualBox $VERS available" |\
        mail -s "VirtualBox $VERS" $EMAIL
        # Save new version
        echo "$VERS" > $FILE
fi

ว้า … ยังไม่ไปถึงใหนเลย … แต่ชักจะยาวเกินไปแล้ว ขอตัดจบแค่นี้ก่อนครับ เดี๋ยวจะกลับมาต่อเรื่องจะ download package ไฟล์ที่เราต้องการจาก download.virtualbox.org ได้ยังไง ใน blog ถัดไปครับ Exciting (กรรมวิธีในการเพิ่มจำนวน blog ทั้งที่มีเนื้อหาที่จะเล่าเท่าเดิม … (ฮา) …)

Comments are closed.