2013/09/18
main 関数の書き方
こちらの記事に触発されて、 C で同じお題のプログラム (echo (1) のサブセット)を書いてみた。
main には殆ど処理を記述せずに
パラメタ解析や割り込みなどの初期設定のみをしてから、
実際のメイン処理(この場合は echo)を実行するというスタンスは同じです。
ただし、今回の例で言えば getopt(3) を利用して
オプション解析を済ませた(実際に echo 出力する)パラメタ群のループは
main 側で行う方が好きかな。
1#include <stdio.h> 2#include <unistd.h> 3 4void echo(const char *p, int nonl) 5{ 6 7 /* 8 * ここは以下の様にすると printf(3)、putchar(3) の呼び出しを 9 * printf(3) の呼び出しのみに変更できソースもスッキリする。 10 * 1 文字の出力を '%s' で変換する無駄が微妙に気になるのだが、 11 * どちらかと言えば改行を出力する事の方が多いと思うので 12 * putchar(3) の呼び出しがない方が良いのか 13 14 printf("%s%s", p, nonl ? "" : "\n"); 15 16 */ 17 18 printf("%s", p); 19 if(!nonl) 20 putchar('\n'); 21 22} 23 24int main(int argc, char *argv[]) 25{ 26 27 int i, 28 nonl = 0; 29 30 while((i = getopt(argc, argv, "n")) != EOF){ 31 switch(i){ 32 case 'n': 33 nonl = 1; 34 break; 35 36 default: 37 break; 38 } 39 } 40 41 for(i=optind; i<argc; i++) 42 echo(argv[i], nonl); 43 44 exit(0); 45 46}
2013/08/02
シェルスクリプトでループ
シェルスクリプトでループ処理をする場合、
最も多用するのは while だと思う。
良く見かけるのは次の様な書き方だろう。
:
while true
do
処理
if 条件
then
break
fi
done
:
勿論この書き方でも問題なく動作するが、
条件がコマンドの戻り値の場合は以下の方が簡潔に記述できる。
コマンドの戻り値が 0 (正常終了の場合) ループを続けたい場合。
:
while コマンド
do
処理
done
:
コマンドの戻り値が 0 以外(正常終了以外の場合) ループを続けるのであれば
while の替わりに until が利用できる。例えば再起動中のリモートサーバに ssh (1) 接続したい場合、 以下の方法で繰り返し接続を試行する事ができる。
until ssh -o 'ConnectTimeout 5' リモートサーバ
do
sleep 10
done
ssh (1) が成功するとリモートサーバから exit した時点で
until の条件が真になるのでループを抜ける事ができる。
2013/07/31
MySQL データベースを Amazon S3 にバックアップするスクリプト
自宅サーバで運用している MySQL データベースのデータを Amazon S3 にバックアップするためのスクリプトを作成したので公開。
今回作成したスクリプトでは、
ローカルディレクトリに YYYYMMDD 型式で 7 世代分のデータをフルダンプし、
毎週日曜日の深夜に Amason S3 に当日分のバックアップを転送している。
mysqldump で取得したバックアップデータに VIEW 情報が含まれていると
データベースのレストア時にエラーが発生する可能性がある様なので、
mysqldump 時に VIEW 定義は除外してダンプを取得し
VIEW 情報のみを別途ダンプする様にしている。
Amason S3 への転送は S3 tools が公開している
s3cmd を利用しているので、
s3cmd と python のインストールは必須。
当然 Amazon S3 も利用できる様にしておく必要がある。
以下のスクリプトは MySQL の接続用パスワードや
Amazon S3 のアクセスキーなどを平文で保存しているので、
ファイルのアクセス権限には十分に注意が必要である。
バックアップは root 権限で実行する様にし
ファイルの権限は 500 に設定しておく事が望ましい。
1#!/bin/sh 2 3# MySQL 用の設定 4database="データベース名" 5user="-uユーザ -pパスワード" 6 7# Amazon S3 用の設定 8backet="backet 名" 9PASSPHRASE="パスフレーズ" 10AWS_ACCESS_KEY_ID="アクセスキーID" 11AWS_SECRET_ACCESS_KEY="SECRET アクセスキー" 12 13# ローカルにバックアップする世代数 14max=7 15# Amazon S3 に転送する曜日指定 (0: 日曜 … 6: 土曜) 16dayofweek=0 17 18# コマンド定義 19ls="/bin/ls -1" 20wc="/usr/bin/wc -l" 21rm="/bin/rm -r" 22head="/usr/bin/head -1" 23mkdir="/bin/mkdir -p" 24 25# ファイルとディレクトリ定義 26logfile="/var/log/`basename ${0}`.log" # ログファイル名 27backupdir="/var/db/backup" # バックアップ先ディレクトリ 28target="`date '+%Y/%m/%d'`" # Amason S3 でバックアップを格納するディレクトリ名 29targetdir="${backupdir}/`date '+%Y%m%d'`" # ローカルでバックアップを格納するディレクトリ名 30backupfile="${targetdir}/all_dump.sql" # バックアップファイル名 31createview="${targetdir}/create_view.sql" 32createtable="${targetdir}/create_table.sql" 33 34# MySQL コマンドの定義 35mysql="/usr/bin/mysql ${socket} ${user} -B -N -s -r " 36mysqldump="/usr/bin/mysqldump ${user} 37 -R --hex-blob --single-transaction" 38sql="select TABLE_NAME from information_schema.TABLES 39 where TABLE_SCHEMA = '${database}' and TABLE_TYPE = 'VIEW';" 40 41# s3cmd の定義 42s3cmd="/usr/bin/s3cmd put -rr" 43export PASSPHRASE AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY 44 45# ロギング開始 46umask 700 47exec > ${logfile} 2>&1 48set -x 49 50# ローカルディレクトリの準備 51# 最大世代数以上の場合は一番古い世代を削除する 52test `${ls} ${backupdir} | ${wc}` -ge ${max} && 53 ${rm} ${backupdir}/`${ls} ${backupdir} | ${head}` 54${mkdir} ${targetdir} 55 56echo "DB backup: start: `date`" 57 58# ダンプから除外するために VIEW を取得し create view 文をダンプする 59for i in `${mysql} ${database} -e "${sql}"` 60do 61 view="${view} --ignore-table=${database}.${i}" 62 ${mysql} ${database} -e "show create view ${i}" 63done > ${createview} 64 65# 全データダンプ 66${mysqldump} ${view} ${database} > ${backupfile} 67 68# create table 文のダンプ 69${mysqldump} --no-data ${view} ${database} > ${createtable} 70 71# 指定された曜日の場合は Amazon S3 に転送する 72# 以下の 1行をコメントとすると 毎日 Amazon S3 に転送する 73test `date '+%w'` -eq ${dayofweek} && 74 ${s3cmd} ${targetdir}/ s3://${backet}/${target}/ 75 76echo "DB backup: end: `date`"
2013/07/30
awk による正規表現にマッチした部分の抜き出し
入力行に "running"、"stopping"、
"stopped"、"pendding" のいずれかの単語が含まれる場合に
その単語を抽出したい場合。
awk (1) の sub()、gsub() 組み込み関数では
後方参照ができないので
マッチしたパターンに応じた変換を一度に行う事ができず、
それぞれのパターンにマッチングさせて処理をするしかない。
awk '
/^INSTANCE.*running/{
print running;
}
/^INSTANCE.*stopping/{
print stopping;
}
/^INSTANCE.*stopped/{
print stopped;
}
/^INSTANCE.*pending/{
print pending;
}
'
しかしこれではあまりにも悲しいのでマニュアルをじっくりと調べた所、
組み込み関数 match() で正規表現にマッチ処理を行うと
組み込み変数 RSTART にマッチした文字の位置、
RLENGTH にマッチした文字列の長さが設定されるので
組み込み関数 substr() と併用する事で
マッチした部分を抽出する事ができる事に気がついた。
awk '
/^INSTANCE/{
if(match($0, /running|stopping|stopped|pending/))
print substr($0, RSTART, RLENGTH);
if(match($0, /ec2.*\.amazonaws\.com/))
print substr($0, RSTART, RLENGTH);
}
'
awk (1) で正規表現によるパターン抽出を行う場合に便利だと思います。
文字列はあくまでも例であって特別な意味を持っていません。
万が一類似する文字列があった場合でもそれは偶然の一致です。
ぐ、偶然ですからねっ(汗
2013/07/09
PATH の扱い
unix 系 OS では ${PATH} 環境変数を参照して
コマンドの検索パスを指定する事ができる。
通常はログイン時にシステムデフォルトのコマンド検索パスが
${PATH} に自動で設定されているが、
ユーザ毎のシェルのログインファイル (.profile 等)で
自分用のコマンド検索パスを追加設定する事が多い。
ここで気をつけるべきは ${PATH} 中のヌルパス ("::") は
カレントディレクトリ (".") と同等に扱われてしまう事だ。
例えば
PATH="${PATH}:${mypath}:${HOME}/bin"
と設定した時に ${mypath} が設定されていない場合
PATH="${PATH}::${HOME}/bin"
と展開されてしまうので、
結果としてカレントディレクトリが ${PATH} に含まれてしまう。この挙動は POSIX (IEEE Std 1003.1, 2004 Edition) の 8.3 Other Environment Variables) にも明記されている。
The prefixes shall be separated by a colon ( ':' ). When a non-zero-length prefix is applied to this filename, a slash shall be inserted between the prefix and the filename. A zero-length prefix is a legacy feature that indicates the current working directory.過去互換性の様だが非常に迷惑な仕様である。
カレントディレクトリをコマンド検索パスに含める事は
どんな場合でもセキュリティ上のリスクを伴うので避けるべきでなので、
PATH を設定する場合は注意が必要だ。
例えば .profile で ${PATH} を設定する場合、
以下の様にする事は防衛手段として悪く無い考えだと思う。
PATH="`echo ${PATH}:${mypath}:${HOME}/bin | sed 's/::*/:/g'`"
2012/12/27
指定された日の曜日を取得する
先日開催された 第2回チキチキ!シェル芸人養成勉強会 の課題の中で自分の中で話題になった事。
指定された日の曜日を取得したい場合、 gnu 版の date (1) がインストールされている場合は 以下のコマンドで取得可能(0 が日曜日を示す)。
$ date -d YYYYMMDD '+%w' 0gnu 版の date (1) がインストールされていない場合でも、 FreeBSD 版の date (1) は独自拡張されているので 以下のコマンドで取得可能だと言う事を教わった(0 が日曜日を示す)。
$ date -j YYYYMMDDHHMM '+%w' 0
但しどちらも posix に準拠していない独自拡張な機能を利用しているため
環境依存となってしまうので、
環境に依存しない方法での解決方法を考えてみた。
日付から曜日を取得するためには ツェラーの公式
という計算式があるので、
posix に準拠したシェルの機能だけでその計算式を実装してみる。
$ y=YYYY; m=MM; d=DD $ test $m -lt 3 && y=$(($y - 1)) && m=$(($m + 12)) $ echo $(($(($y + $y/4 - $y/100 + $y/400 + $(($((13 * $m + 8))/5)) + $d)) % 7))年と月の値によって調整が必要なのでワンライナーにはならないのが残念だけど、 基本的には単純な四則演算なのでシェルの機能のみで実装が可能だ。
これで gnu 版の date (1) がインストールされていない環境でも 任意の日付の曜日が簡単に取得できる!。
2012/12/26
dog (1)
以前、某雑誌のシェルスクリプト大喜利に投稿したネタ。
こんな感じのお題に対する回答。
cat コマンドの作者が遺言を遺しました。
「私の人生における最大の公開は、 dog コマンドを作り忘れてしまったことだ。 あぁ誰か作ってくれぇー。ガクッ」
さぁ、一体どんなコマンド?
お題がネタっぽいので回答もネタっぽくしてみた。
more (1) を拡張して less (1) が、 yacc (1) を拡張して bison (1) が作られた様に、 dog (1) は cat (1) が拡張されたものという発想で http、https そして ftp といった schema に対応した cat (1) というスクリプトにしてみた。
内容はとても単純なので cat → dog という発想だけが勝負のスクリプトである。
雑誌では割愛されてしまったネタとしてのマニュアルも掲載してみる。
というか、実はマニュアルの方が書きたかったという…(笑
1#!/bin/sh 2# 3# NAME 4# dog -- concatenate and print files 5# 6# SYNOPSIS 7# dog [cat options] [file ...] 8# 9# DESCRIPTION 10# Dog is a file concatenate and print command in the style of cat(1). 11# It should be upwardly compatible with original cat. 12# 13# The dog utility reads files sequentially, writing them to the standard 14# output. The file operands are processed in command-line order. If file 15# has protocol schema such as 'http://', 'https://' or 'ftp://', dog utility 16# gets the file from remote system and display it, otherwise dog assumes 17# local file. The dog utility uses wget(1), curl(1), or lynx(1) to retrieve 18# the file from remote system. If dog utility could not find these commands 19# from standard command path, disable remote file display. 20# All option of dog is same as cat(1) except '-h'. 21# 22# EXIT STATUS 23# The dog utility exits 0 on success, and >0 if an error occurs. 24# 25# SEE ALSO 26# Rob Pike, "UNIX Style, or cat -v Considered Harmful", USENIX Summer 27# Conference Proceedings, 1983. 28# 29# STANDARDS 30# The dog utility is *NOT* complient with the IEEE Std 31# 1003.2-1992 (``POSIX.2'') specification, even now and forever. 32# 33 34curl="-s -o -" 35wget="-q -O -" 36lynx="-source" 37 38# get command name and path 39for i in wget curl lynx 40do 41 for j in /bin /usr/bin /usr/local/bin /opt/bin /opt/local/bin 42 do 43 if [ -x ${j}/${i} ] 44 then 45 command="${j}/${i} `eval echo '$'${i}`" 46 break 2 47 fi 48 done 49done 50 51# args 52while [ ${1} != "" ] 53do 54 case ${1} in 55 -h ) 56 sed -n '2,/^$/s/^#//p' ${0} 57 exit 1 58 ;; 59 -- ) 60 shift 61 break 62 ;; 63 -* ) 64 opt="${opt} $1" 65 ;; 66 * ) 67 break 68 ;; 69 esac 70 shift 71done 72 73for i in $* 74do 75 if expr ${i} : "https*://" > /dev/null 76 then 77 if [ -n "${command}" ] 78 then 79 ${command} ${i} | cat ${opt} 80 else 81 echo "${0##*/}: cannot get remote file: ${i}" 1>&2 82 fi 83 elif expr ${i} : "ftp*://" > /dev/null 84 then 85 case ${command} in 86 *wget*|*curl* ) 87 ${command} ${i} | cat ${opt} 88 ;; 89 * ) 90 echo "${0##*/}: cannot get remote file: ${i}" 1>&2 91 ;; 92 esac 93 else 94 cat ${opt} ${i} 95 fi 96done
今回のシェルスクリプト大喜利にも投稿したので、 某雑誌が発売されたら紹介する予定。
2012/11/30
IPv4 アドレスがネットワークに属しているか調べる
ネットマスクとはその名の通り IPv4 アドレスのうち、
どこまでのビットがネットワークアドレスなのかを示しているので、
IPv4 アドレスとネットマスクの論理和はネットワークアドレスとなる。
そのため、取得した論理和とネットワークアドレスが等しい場合は
IPv4 アドレスはネットワークに属す事になる。
C で実装する場合はこんな感じかな。
1int checkAddr(const char *network, const char *netmask, const char *ipaddr) 2{ 3 4 struct in_addr net, 5 mask, 6 addr; 7 8 if(inet_aton(network, &net) && 9 inet_aton(netmask, &mask) && 10 inet_aton(ipaddr", &addr)) 11 return((addr.s_addr & mask.s_addr) == (net.s_addr & mask.s_addr)); 12 else 13 return(0); 14 15}
ちなみに仕事で実装した java のコード。
1boolean checkAddr(String network, String netmask, String ipaddr) 2{ 3 4 try { 5 int n = 0, 6 m = 0, 7 a = 0; 8 byte[] net = InetAddress.getByName(network).getAddress(), 9 mask = InetAddress.getByName(netmask).getAddress(), 10 addr = InetAddress.getByName(ipaddr).getAddress(); 11 12 for(int i=0; i<4; i++) 13 n |= ((int)net[i] & 0xff) << (8 * (3 - i)); 14 for(int i=0; i<4; i++) 15 m |= ((int)mask[i] & 0xff) << (8 * (3 - i)); 16 for(int i=0; i<4; i++) 17 a |= ((int)addr[i] & 0xff) << (8 * (3 - i)); 18 19 return((a & m) == (n & m)); 20 21 } catch (Throwable e){ 22 return false; 23 } 24 25}java はそれほど詳しくないのでコーディングが冗長だけど、 取りあえず動作している(気がする)。
2012/11/02
CentOS 6.3 インストール直後にする作業
仕事では Linux サーバ、特に CentOS の導入~初期設定の機会が多いので、 全ての CentOS 6.3 サーバの導入時に必ず行っている作業をメモする。
インストール作業は CentOS 6.3 の DVD から起動して行う。
CentOS 6 からはテキストベースのインストーラの場合、
パーティションの設定やファイルシステムの指定、
初期インストールされるパッケージの追加・削除など指定できないので、
GUI を利用した通常のインストールを実行する。
インストールが終了したら初期環境設定を行う。
以下の作業は CentOS 6.3 を導入したマシンでほぼ必ず実施する作業。
- 自分のユーザを作製する
-
# adduser アカウント # password アカウント
- 自分のアカウントを wheel グループに追加する
-
sudo (1) 可能な様に自分のアカウントを
wheel グループに追加する。
# (rm /etc/group; sed 's/^wheel.*/&,アカウント/g' > /etc/group) < /etc/group - sudo(1) の設定を変更する
-
sudo(1) しても元の環境変数を保持する様設定
Defaults env_reset を Defaults !env_reset に変更 # Defaults env_keep += "HOME" のコメント記号 `#' を削除wheel グループのアカウントのみ sudo (1) 可能にする# %wheel ALL=(ALL) ALL のコメント記号 `#' を削除# visudo - termcap を使用するアプリケーション対応
-
# ln -s /usr/lib/libtinfo.so /usr/lib/libtermcap.so.2 - selinux を無効にする
-
# (rm /etc/sysconfig/selinux; sed 's/^SELINUX=.*/SELINUX=disabled/' > /etc/sysconfig/selinux) < /etc/sysconfig/selinux# ex -s /etc/syconfig/selinux << EOF > /^SELINUX=/s/.*/SELINUX=disabled > wq > EOF2012/11/09 追記
CentOS の /etc/sysconfig/selinux は /etc/selinux/config へのシンボリックリンクで 実際は /etc/selinux/config を参照しているのだが、 rm (1) と sed (1) を使った方法だと /etc/sysconfig/selinux が通常ファイルになって 書き換わってしまい、元の /etc/selinux/config が 変更されていないために selinux が無効にならない という問題を指摘して頂いたので編集方法を修正しました。
- システム更新
-
# yum update - 最低限必要なソフトウェアのインストール
-
システムを運用する上でこれだけは必要だとうソフトウェアを導入する。
# yum install openssh-clients libtermcap-devel tcpdump # yum install ntpdate telnet wget tcpdump unzip mlocate rsync bind-utils
- 開発環境のインストール
-
ソフトウェアを開発する場合は導入する。
通常はサーバでは開発しないので導入は不要な筈…
# yum install make gcc bison flex - ファイアウォールの設定
-
グローバル環境に晒されるサーバであれば
最低限のファイアウォールは設定する必要がある。
基本的には以下のポリシーで必要に応じて追加・削除する。
#!/bin/sh iptables=/sbin/iptables # 全て初期化 ${iptables} -F # デフォルトルール ${iptables} -P INPUT DROP ${iptables} -P OUTPUT ACCEPT ${iptables} -P FORWARD DROP # ループバックを有効にする ${iptables} -A INPUT -i lo -p all -j ACCEPT # 接続済みのパケットを受け付ける ${iptables} -A INPUT -p tcp -m state --state ESTABLISHED,RELATED -j ACCEPT # http, httpsはどこからでもアクセス可 ${iptables} -A INPUT -p tcp --dport 80 -j ACCEPT ${iptables} -A INPUT -p tcp --dport 443 -j ACCEPT ${iptables} -A INPUT -p tcp --dport 8080 -j ACCEPT ${iptables} -A INPUT -p tcp --dport 9080 -j ACCEPT # dns パケットを許可 ${iptables} -A INPUT -p tcp --sport 53 -j ACCEPT ${iptables} -A INPUT -p udp --sport 53 -j ACCEPT ${iptables} -A INPUT -p tcp --dport 53 -j ACCEPT ${iptables} -A INPUT -p udp --dport 53 -j ACCEPT # ntp パケットを許可 ${iptables} -A INPUT -p tcp --dport 123 -j ACCEPT ${iptables} -A INPUT -p udp --dport 123 -j ACCEPT # そのほか必要なルールを記載 : :
上記設定を /tmp/firewall.sh に格納した場合、 ファイアウォールを有効にして設定をセーブする。# sh /tmp/firewall.sh # /etc/init.d/iptables save iptables: ファイアウォールのルールを /etc/sysconfig/iptableに保存中: [ OK ]
- 起動サービスの設定
-
起動サービスを設定する。
基本的には atd crond iptables network ntpd rsyslog sshd のみを有効にする
# for i in `chkconfig --list | awk '/:on/{ print $1 }'` > do > case $i in > atd|crond|iptables|network|ntpd|rsyslog|sshd ) > ;; > * ) > chkconfig $i off > chkconfig --del $i > ;; > esac > done
ここまで設定して再起動する。
MTA や httpd など固有のサービスは個々に設定する。
2012/10/31
hbstudy まとめ
先日参加した hbstudy #38 ハンズオンの
課題 の幾つかを
シェルのみ 縛りで回答してみる。
流石にシェルのみで解く場合はワンライナーは無理なので、
普通のシェルスクリプトの型式で記述している。
- 問題1: ユーザの抽出
-
/etc/passwd から、ユーザ名を抽出したリストを作って下さい
1IFS=: 2while read id other 3do 4 echo ${id} 5done </etc/passwd
IFS を : に変更して /etc/passwd を 直接フィールド分割して変数 u に read している。
- 問題2: ユーザの抽出
-
/etc/passwd から、次を調べて下さい。
ログインシェルが bash のユーザと sh のユーザどちらが多い?
1IFS=: 2while read id p u g e d shell 3do 4 case ${shell} in 5 */sh ) 6 sh=$((${sh} + 1));; 7 */bash ) 8 bash=$((${bash} + 1));; 9 esac 10done < /etc/passwd 11echo "bash: " ${bash} 12echo "sh: " ${sh}
問題:1 同様に IFS を : に変更して /etc/passwd を直接フィールド分割して 変数 u、shell に read し、 変数 sh と bash に出現回数をカウントしている。
- 問題5: FizzBuzz
-
1,2,3,4,5…と数えていって…
- 3 の倍数だったら数字の代わりに「Fizz」
- 5 の倍数だったら数字の代わりに「Buzz」
- 15 の倍数だったら数字の代わりに「FizzBuzz」
1i=1 2while [ ${i} -lt ${1:-100} ] 3do 4 if [ $((${i} % 15)) -eq 0 ] 5 then 6 echo -n "FizzBuzz," 7 elif [ $((${i} % 5)) -eq 0 ] 8 then 9 echo -n "Buzz," 10 elif [ $((${i} % 3)) -eq 0 ] 11 then 12 echo -n "Fizz," 13 else 14 echo -n "${i}," 15 fi 16 i=$((${i} + 1)) 17done 18echo
素直に 1 から $1 (指定されていない場合は 100) までを $((…)) にて % 演算子で剰余計算して出力している
- 問題8: CPU 使用率
-
top の出力からどのユーザが
何% CPU を使用しているか集計して下さい。
1exec 3<&0 0<< EOF 2`ps aux` 3EOF 4 5while read u p c other 6do 7 if [ "${u}" != "USER" ] 8 then 9 case ${users} in 10 *${u}* ) 11 ;; 12 * ) 13 users="${users} ${u}" 14 ;; 15 esac 16 eval "$u=\$((\$$u + ${c%%.*}))" 17 fi 18done 19 20for i in ${users} 21do 22 echo "${i} : `eval echo '$'$i`" 23done
CPU 使用率は小数点以下切り捨てで計算している。
出現したユーザID を users 変数に格納しておく。
eval と $((…)) を利用して、 ユーザID を変数名とした変数に CPU 利用率を集計している。
最後に for ループで users に格納された ユーザID とユーザIDを変数名とした変数に格納されている 集計値を表示している。
FreeBSD では top -b -n 1 が利用不可なので ps aux の出力を集計する
全てのスクリプトは FreeBSD 上の /bin/sh で動作確認済み。
手元に Linux 環境が存在しないので Linux での動作は未確認だけど、
posix 機能だけしか使用していない(筈)なので Linux でも動作すると思う。

