gnu,bsdコマンドの差を吸収しよう
linuxとその他のunix、例えばmacなど両方を使う
環境の人も多いだろう。
その場合はgnuコマンドなのか、bsdコマンドなのかで混乱することも多い。
また、LinuxでもDebian系はgawkでなく、mawkという少機能だが、速度が改善されている
awkを使っている。普通のプロジェクトでmawkじゃないとダメということはなく、
むしろgawkで使いたい関数が使えない弊害のほうが大きいため、これもgawkで置き換える。
ほとんどの場合はgnuコマンドの方が使い勝手が良く、
ソースコードも簡潔になる。
この二つのコマンドの差を吸収する方法を書く。
やり方
コマンド名のfunctionを定義して、そのコマンドの中でgnuコマンドを実行すると
gnuコマンドとbsdコマンドの差を吸収できる。
aliasでコマンド名を定義すると、対話形式のみで有効になり、
ファイルを読み込んで実行することができないので、functionで定義する方法しか取れない。
下のような関数が良いだろう。
function sed {
gsed "$@"
}
またこの上書き処理を~/.bashrcなどに直接書くと影響範囲が広過ぎて
既存の処理を邪魔する可能性がある。
よって、使いたいときにだけgnu,bsdコマンドの吸収する処理を読んで、
好きなときに変更を破棄する処理があると良い。
.bashrcに上書き関数群を読み込む関数の定義を書くか、
関数群を読み込むファイルをsourceすると上手くいくか。
このやり方だと、子プロセスで差を吸収する処理を読んでも、
親やその他のプロセスに影響がないため、使いやすいはず。
ソースコード
# 関数群を読み込むコマンド
source $HOME/bash/function/read_function
# $HOME/bash/function/配下のファイルをすべて読み込む関数
function read_function {
local function_dir=$HOME/bash/function
eval "$(
ls ${function_dir} |
grep -v .md |
grep -v read_function |
xargs -I {} echo source ${function_dir}/{};
)"
unset -f read_function
}
read_function
上のread_functionにより読み込まれる。
#!/bin/bash
#
# gnu command util.
#######################################
# set alias gnu command for Mac and BSD.
# Globals:
# GNU_ALIAS
# Arguments:
# None
# Outputs:
# None
# Returns:
# 0 if set alias, non-zero on error.
# Example:
# gnu_alias # => you use use sed
#######################################
function gnu_alias {
for arg in "$@"; do
case "$arg" in
-h|--help)
function usage() {
cat 1>&2 << END
gnu_alias
output search engine setting
USAGE:
gnu_alias [FLAGS] [OPTIONS]
FLAGS:
-h, --help Prints help information
OPTIONS:
--debug Set bash debug Option
END
unset -f usage
}
usage
return
;;
--debug)
# set debug
set -x
trap "
set +x
trap - RETURN
" RETURN
;;
*)
;;
esac
done
# you use Darwin, set alias for use Gnu sed, awk, xargs
if uname | grep -e Darwin -e BSD > /dev/null; then
if ! gnu_exists; then
echo "Any Gnu command is not exists." >&2
return 1
fi
function getopt {
if uname | grep -e Open > /dev/null; then
# openbsd
/usr/local/bin/gnugetopt "$@"
elif uname | grep -e Free > /dev/null; then
# freebsd
/usr/local/bin/getopt "$@"
elif uname | grep -e Darwin > /dev/null; then
# macos
# darwin
/usr/local/opt/gnu-getopt/bin/getopt "$@"
fi
}
# alias not using shellscript in norepl.
# and using function for alternative alias.
function sed {
gsed "$@"
}
function awk {
gawk "$@"
}
function xargs {
gxargs "$@"
}
function find {
gfind "$@"
}
function date {
gdate "$@"
}
function cut {
gcut "$@"
}
function df {
gdf "$@"
}
export GNU_ALIAS=yes
# debian default awk is mawk.
# alias gawk.
elif ls /etc | grep debian_version >> /dev/null; then
if ! gnu_exists; then
echo "Any Gnu command is not exists." >&2
return 1
fi
function awk {
gawk "$@"
}
export GNU_ALIAS=yes
fi
}
#######################################
# check exists gnu command alias gnu command for Mac and BSD.
# gsed, gawk, gxargs, gfind, ... and many
# Globals:
# None
# Arguments:
# None
# Outputs:
# None
# Returns:
# 0 if exists gnu commands, non-zero on error.
# Example:
# gnu_exists # => you use use sed
#######################################
function gnu_exists {
# you use Darwin, set alias for use Gnu sed, awk, xargs
if uname | grep -e Darwin -e BSD > /dev/null; then
# gsedがなかったら、return 1
# gnu-getopt
if uname | grep -e Open > /dev/null; then
# openbsd
if ! type "/usr/local/bin/gnugetopt" > /dev/null; then
echo "gnu-getopt is not exists." >&2
return 1
fi
elif uname | grep -e Free > /dev/null; then
# freebsd
if ! type "/usr/local/bin/getopt" > /dev/null; then
echo "gnu-getopt is not exists." >&2
return 1
fi
elif uname | grep -e Darwin > /dev/null; then
# macos
# darwin
if ! type "/usr/local/opt/gnu-getopt/bin/getopt" > /dev/null; then
echo "gnu-getopt is not exists." >&2
return 1
fi
else
echo "unknown Unix!" >&2
return 1
fi
if ! type "gsed" > /dev/null; then
echo "gsed is not exists." >&2
return 1
fi
if ! type "gawk" > /dev/null; then
echo "gawk is not exists." >&2
return 1
fi
if ! type "gxargs" > /dev/null; then
echo "gxargs is not exists." >&2
return 1
fi
if ! type "gfind" > /dev/null; then
echo "gfind is not exists." >&2
return 1
fi
if ! type "gdate" > /dev/null; then
echo "gdate is not exists." >&2
return 1
fi
if ! type "gcut" > /dev/null; then
echo "gcut is not exists." >&2
return 1
fi
if ! type "gdf" > /dev/null; then
echo "gdf is not exists." >&2
return 1
fi
# you use debian distribution, set alias awk.
elif ls /etc | grep debian_version >> /dev/null; then
if ! type "gawk" > /dev/null; then
echo "gawk is not exists." >&2
return 1
fi
fi
}
#######################################
# unalias gnu command for Mac.
# Globals:
# GNU_ALIAS
# Arguments:
# None
# Outputs:
# None
# Returns:
# 0 if thing was deleted, non-zero on error.
# Example:
# gnu_unalias # => you use use sed
#######################################
function gnu_unalias {
# you use Darwin, set alias for use Gnu sed, awk, xargs
if uname | grep -e Darwin -e BSD > /dev/null; then
unset -f getopt
unset -f sed
unset -f awk
unset -f xargs
unset -f find
unset -f date
unset -f cut
unset -f df
unset GNU_ALIAS
fi
# you use debian distribution, set alias awk.
if ls /etc | grep debian_version >> /dev/null; then
unset -f awk
unset GNU_ALIAS
fi
}
使い方
好きなときに下記のように対話形式で読んで下記のように破棄すると良い。
# overwrite bsd command to gnu command.
gnu_alias
# gnuコマンドに置き換わっているので-iでsedの上書きができる。
sed -i.org /etc/hoge
# gnuコマンドが上書きされているかどうかは下記の環境変数に入っている。
# これをもとに判断する。
echo $GNU_ALIAS
# 関数の上書き解除
gnu_unalias
下記のように他のシェルスクリプトに組み込むのも良い。
function g++find_include {
source $(dirname $0)/../function/gnu_alias
if ! gnu_alias; then
return 1;
fi
...
}
g++find_include
シェルスクリプト呼び出し。
bash g++find_include.sh
Discussion