7
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

bashの各種コマンドを編集するシェルスクリプト

Last updated at Posted at 2015-02-06

bashの各種のコマンドを、簡単に編集できるようにしたい。

環境はMac。

コマンドの種類

bashで利用できるコマンドには、以下の5種類がある。

  1. エイリアス
  2. 関数
  3. ファイル
  4. 予約語
  5. シェル組み込みコマンド

このうち、自分で作成できるのは1〜3である。これらを一括して編集できるのが理想。

typeコマンドによるコマンドの判別

コマンドが1〜5のどれであるかは、typeコマンドによって判断できる。

# -tオプションでタイプのみを表示
$ type somealias # エイリアス
somealias is aliased to `echo "somealias"'
$ type -t somealias
alias

$ type somefunc # 関数
somefunc is a function
somefunc ()
{
    echo "somefunc"
}
$ type -t somefunc
function

$ type ls # ファイル
ls is /bin/ls
$ type ls # ハッシュされたファイル
ls is hashed (/bin/ls)
$ type -t ls
file
$ type -p ls # パスのみを出力。whichだとパスが通っていても出ない場合がある
/bin/ls

$ type for # 予約語
for is a shell keyword
$ type -t for
keyword

$ type type # 組み込みコマンド
type is a shell builtin
$ type -t type
builtin

ファイルをを何度か実行するとログイン中のシェルでハッシュされる。ハッシュされたものはファイルである。

ファイルがバイナリであるか確認

ファイルがバイナリである場合、エディタで直接編集することはできない。よって、コマンドがバイナリファイルであった場合、除外する必要がある。

あるファイルがバイナリであるかどうかは、fileコマンドで判別する。

# -bオプションで属性のみを表示
$ file -b someprog # テキストファイル(編集可能)
Bourne-Again shell script text executable

$ file -b $(type -p ls) # 'text'を含まないものはバイナリ(編集不可)
Mach-O 64-bit executable x86_64

関数化

typeコマンドの結果を取得し、それに応じて処理するシェル関数を作成する。

このスクリプト自体は、ファイルではなく関数でなければならない。
イリアスと関数の変更を反映するためにsourceコマンドを実行するが、ファイルから実行すると、sourceが別のプロセスで実行されてしまい、カレントシェルに変更が反映されないため。

編集は、VimまたはMacVimで行う。

  • エイリアスまたは関数の場合、編集終了を関知してsourceするのを容易にするため、Vimを使う。
  • プログラムの場合、編集と実行を平行して行えるよう、MacVimを使う。
  • 色つきで出力するのにGNU sedを使用。
  • 機能を増やしすぎた。
# in ~/.bashrc
# export bash_alias=~/.bash/conf/alias-init.bash
# export bash_function=~/.bash/conf/function-init.bash
# export bindir=~/shellsctipts
# export PATH=$PATH:$bindir:./bin
# source "$bash_alias"
# source "$bash_function"

ec () { #edit shell commands
  local dflag=0
  local pflag=0
  local OPTIND_OLD="$OPTIND"
  local OPTIND=1
  usage () {
    echo "Usage: ec [-dph] <comand name>" 1>&2
    echo "-d: delete command." 1>&2
    echo "-p: print aliased to/function or 'what' is file, and copy code."  1>&2
    echo "-h: print help." 1>&2
  }
  while getopts dph OPT
  do
    case $OPT in
      d)
        dflag=1
        ;;
      p)
        pflag=1
        ;;
      h)
        usage
        return 0
        ;;
      ?)
        usage
        return 1
        ;;
    esac
  done 
  shift $((OPTIND - 1))
  OPTIND="$OPTIND_OLD"
  if [ -z "$1" ]; then
    echo "ERROR: input command name to edit" 1>&2
    return 1
  fi
  if ! type "$1" >&/dev/null; then
    echo "ERROR: Undifined command." 1>&2
    return 1
  fi
  case "$(type -t "$1")" in
    "function" )
      if [ "$pflag" = 1 ]; then
        type "$1" | sed -e 1d -e 's/;$//g' | tee >(pbcopy)
        return 0
      fi
      if [ "$dflag" = 0 ]; then
        vim "$bash_function" +"/^$1 ()"
      else
        echo -e "function deleted: \033[032;m$1\033[0m" 1>&2
        sed -i '' "/^$1 () {/,/^}/d" "$bash_function" 1>&2
      fi
      source ~/.bashrc
      ;;
    "alias" )
      if [ "$pflag" = 1 ]; then
        type "$1" | sed -e 's/.* to `//' -e "s/'$// | tee >(pbcopy)" 1>&2
        return 0
      fi
      if [ "$dflag" = 0 ]; then
        vim "$bash_alias" +"/^alias $1="
      else
        gsed -n "s/^alias \($1=.*\)/alias deleted: \x1b[33;m\1\x1b[0m/p" "$bash_alias" 1>&2
        gsed -i "/^alias $1=/d" "$bash_alias"
      fi
      source ~/.bashrc
      ;;
    "file")
      local cmdpath="$(type -p "$1")"
      if file -b "$cmdpath" | grep -q 'text'; then
        if [ "$pflag" = 1 ]; then
          what "$cmdpath"
          pbcopy < "$cmdpath"
          return 0
        fi
        if [ "$dflag" = 1 ]; then
          echo -n "rm: "; rm -v "$(readlink "$cmdpath")"
          echo -n "rm: "; rm -v "$cmdpath"
          return 0
        fi
        mvim "$cmdpath"
      else
        echo "Not text/script file" 1>&2
        return 1
      fi
      ;;
    "keyword"|"builtin")
      echo "$1 is shell keyword or builtin." 1>&2
      return 1
      ;;
    * )
      echo "Unexpected error." 1>&2
      type "$1"
      return 1
      ;;
  esac
}

参考

補足

7
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?