2013年12月6日 星期五

Bash 內建的 getopts 與外部的 getopt 的使用方式

通常在 GNU/Linux 系統底下使用 command 時都會有帶一些額外的參數,像是以下的例子:

$ echo `seq 0 9` | xargs -n1 | wc -l

利用 `seq 0 9` 產生出 0 到 9 的數字,然後 echo 輸出,再用 xargs -n1 利用空白分開每個數字插入換行符號,然後再導到 wc -l 去計算行數。(其實寫成 `seq 0 9 | wc -l` 也有同樣的效果,利用 hexdump -C 就可以看出其中的不同)

其中的 wc -l 也可以寫成 wc --lines 這樣更清楚、更容易理解。

如果說我們想要利用 Bash shell 寫一個同樣的功能,就可以寫成下面這樣:

#!/bin/bash

while getopts l name; do
    case "$name" in
        ('l')
            line=1
            ;;
    esac
    shift
done

if [ -n "$line" ]; then
    awk 'END { print NR }' "$@"
fi

跟原本的 wc -l 提功同樣功能只是換成使用 awk 這個指令來計算行數。

然而 Bash 內建的 getopts 無法直接提供 --lines 這樣的使用方式,於是就可以改用外部的 getopt 指令來達成。

#!/bin/bash

set -e
eval set -- $(getopt -o l -l "lines" -- "$@")
set +e

while :; do
    case "$1" in
        ('-l'|'--lines')
            line=1
            ;;
        ('--')
            shift
            break
            ;;
    esac
    shift
done

if [ -n "$line" ]; then
    awk 'END { print NR }' "$@"
fi

如果說要利用 Bash 內建的 getopts 寫一個 xargs -n1 這樣的功能,則可以寫成以下這樣:

#!/bin/bash

while getopts n: name; do
    case "$name" in
        ('n')
            max="$OPTARG"
            ;;
    esac
    [ "$OPTIND" = 2 ] && shift
    [ "$OPTIND" = 3 ] && shift 2
done

if [ -n "$max" ]; then
    awk "{for (i = 1 ; i <= NF ; i++) { if (i % $max == 0) printf \"%s\\n\", i; else printf \"%s \", i } }" "$@"
fi

如果要支援 xargs --max-lines=1 這樣的使用方式,則可以利用外部的 getopt 改寫成以下這樣:

#!/bin/bash
# filename: xargs.sh

set -e
eval set -- $(getopt -o "n:" -l "max-lines:" -- "$@")
set +e

while :; do
    case "$1" in
        ('-n'|'--max-lines')
            max="$2"
            shift 2
            ;;
        ('--')
            shift
            break
            ;;
    esac
done

if [ -n "$max" ]; then
    awk "{for (i = 1 ; i <= NF ; i++) { if (i % $max == 0) printf \"%s\\n\", i; else printf \"%s \", i } }" "$@"
fi

這樣就可以使用 `xargs.sh --max-lines=1` 了。

2013年12月4日 星期三

Debian/Ubuntu 無人值守的系統更新

Debian/Ubuntu 上面有一個套件叫做 unattended-upgrades - automatic installation of security upgrades 可以用來設定系統的自動更新,這對於一些特別講究系統安全的伺服器特別有用。

以 Ubuntu 12.04 為例,安裝完成及在下面 APT::Periodic::Unattended-Upgrade 打開之後,預設上只會做安全更新,但是我想要它做一般性的系統更新,於是就修改 /etc/apt/apt.conf.d/50unattended-upgrades

// Automatically upgrade packages from these (origin:archive) pairs
Unattended-Upgrade::Allowed-Origins {
        "${distro_id}:${distro_codename}-security";
        "${distro_id}:${distro_codename}-updates";
//      "${distro_id}:${distro_codename}-proposed";
//      "${distro_id}:${distro_codename}-backports";
};

// Do automatic removal of new unused dependencies after the upgrade
// (equivalent to apt-get autoremove)
Unattended-Upgrade::Remove-Unused-Dependencies "true";

// Automatically reboot *WITHOUT CONFIRMATION* if a
// the file /var/run/reboot-required is found after the upgrade
Unattended-Upgrade::Automatic-Reboot "true";

簡單說就是包含使用 precise-updates 上面的更新,更新之後再用 apt-get autoremove 把多餘的套件移除掉,如果有些更新需要重開機才會生效的話,就重開機吧。

然後再修改一下 /etc/apt/apt.conf.d/10periodic

APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Download-Upgradeable-Packages "1";
APT::Periodic::AutocleanInterval "7";
APT::Periodic::Unattended-Upgrade "1";

意思是每日檢查更新,如果有更新的話先下載,每週自動清除不需要的套件快取,使用無人值守自動更新。

關於 linux kernel 的更新,有一個腳本程式 /etc/kernel/postinst.d/apt-auto-removal 產生 /etc/apt/apt.conf.d/01autoremove-kernels,用來保留當下正在使用、或是最新安裝、或是上一份使用的 linux kernel。

至於詳細的運作細節則可以參考 /etc/cron.daily/apt 裡面的內容。

2013年12月2日 星期一

VirtualBox Guest 裡面共用資料夾的自動掛載

VirtualBox 有提供一個方便的功能,能將 Host 的某個資料夾自動掛載到 Guest 裡面使用,只是自動掛載的權限不是預設的使用者。

sylee@vbox:~$ mount
/dev/sda1 on / type ext4 (rw,errors=remount-ro)
proc on /proc type proc (rw,noexec,nosuid,nodev)
sysfs on /sys type sysfs (rw,noexec,nosuid,nodev)
none on /sys/fs/fuse/connections type fusectl (rw)
none on /sys/kernel/debug type debugfs (rw)
none on /sys/kernel/security type securityfs (rw)
udev on /dev type devtmpfs (rw,mode=0755)
devpts on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=0620)
tmpfs on /run type tmpfs (rw,noexec,nosuid,size=10%,mode=0755)
none on /run/lock type tmpfs (rw,noexec,nosuid,nodev,size=5242880)
none on /run/shm type tmpfs (rw,nosuid,nodev)
vbox on /media/sf_vbox type vboxsf (gid=999,rw)
sylee@vbox:~$ id
uid=1000(sylee) gid=1000(sylee) groups=1000(sylee),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),111(lpadmin),112(sambashare)

這時候只要參考以前寫過的『如何解決在 Ubuntu 上面安裝 VirtualBox 後缺少 vboxusers 群組權限的問題』,將預設的使用者加入到 vboxsf 這個群組裡面,再重新登入後,就可以自由地使用 /media/sf_vbox 底下的檔案了。

sylee@vbox:~$ sudo usermod -a -G vboxsf sylee

隨意拿了 linux-generic-lts-quantal_3.5.0.44.50_amd64.deb linux-signed-generic-lts-quantal_3.5.0.44.50_amd64.deb linux-signed-image-generic-lts-quantal_3.5.0.44.50_amd64.deb linux-image-3.5.0-44-generic_3.5.0-44.67~precise1_amd64.deb linux-signed-image-3.5.0-44-generic_3.5.0-44.67~precise1_amd64.deb 來測試。

使用 vboxsf 來複製檔案。

real    0m0.661s
user    0m0.004s
sys     0m0.284s

使用 sshfs 來複製檔案。

real    0m2.276s
user    0m0.000s
sys     0m0.103s

sshfs 掰~