#
ドキュメント

Document

自分のための備忘録です。

シェルスクリプトの基礎

シェルスクリプト実行方法

  • shコマンドを使用:$ sh ./test.sh
  • .(ドット)コマンドを使用: $ . ./test.sh
  • execコマンドを使用: $ exec {{command}}
  • シェルスクリプトにシバング(#!)を記載 + 実行権付与:例:!# /bin/bash

shを使った実行例

sample.sh

HELLO=hello
echo $HELLO

別プロセスでスクリプトが実行されるため、スクリプト実行後にカレントシェルでsample.shで定義された変数を使用できない。

$ sh ./sample.sh
hello
$ echo $HELLO
// 何も表示されない

.(ドット)を使った実行例

別プロセスを作成せずにカレントシェルのプロセスでスクリプトが実行されるため、スクリプト実行後にカレントシェルでsample.shで定義された変数を使用できる。

変数

基本

ポイントをまとめると以下のとおりとなる。
  1. = を使う
  2. 値の設定時は変数名の先頭に $ を付けない ($ は参照時のみ)
  3. = の前後にスペースを入れない (前後にスペースがあるとエラー)
  4. 型は存在しない (declare コマンドや typeset コマンドで似たようなことができるが推奨はしない)
  5. 変数名の大文字・小文字は区別される (VAR と var は別物)

特に「2」は初心者が犯しがちなミスなので注意すること。

変数を使用する | UNIX & Linux コマンド・シェルスクリプト リファレンス

$(command)

command出力結果を変数へ代入するためには、$(command)と記載します。

output=$(echo 'abc');echo $output;
// abc

文字

文字 内容
' すべてキャラクタがエスケープされます。
" $で変数を展開します。$, `,\, "はエスケープする必要があります。
クォートなし 要調査

簡単な例1

$ vi script.sh

#!/bin/bash
if [ -f file.txt ]; then
  while read LINE
  do
    echo $LINE
  done < file.txt
fi

script.shを直接実行するために、オーナーの実行権限を許可します(ファイルのデフォルトのパーミッションは多くの場合644なので、実行権限を許可する必要があります)。

$ chmod u+x script.sh

サンプルスクリプトで読み込むファイル(file.txt)を作成します。

$ cat >> file.txt
aaa
bbb
ccc
Ctrl + D

スクリプト実行します。

$ ./script.sh
aaa
bbb
ccc

$ script.shでは実行できません。これは環境変数PATHへ登録しているパスは.(カレントディレクトリ)なので、.の指定が必要なためです。

簡単な例2

#!/bin/bash
if [ -f file.txt ]; then
  total=0
  while read LINE
  do
    total=$(expr $total +  $LINE)
  done < file.txt
fi
echo $total # 現在のシェルはループ内の値をループが抜けても参照できる

file.txt

2
4
6
$ ./script.sh
12

環境変数

環境変数は、すべてのプロセスから参照できる変数です。
環境変数の一覧は、printenvコマンドで確認できます。

$ printevn

環境変数の例 PATH

変数PATHの値を確認します。

$ echo ${PATH}

.bash_profile

パスを通すとは、シェル設定ファイル(.bash_profile.zshrcで、環境変数PATHにパスを追加することです。   exportで環境変数(この場合はPATH)を更新します。

PATH=$PATH:/path/to/add
export PATH

PATHのTIPS

(1) PATHの優先順位を確認

$ cat /etc/paths
// 優先度の高い順に表示

例えば以下のように、.bash_profileで優先順位を変更できます。

PATH=/path/to/dir:$PATH
export PATH

(2) sourceコマンド

.bash_profileを変更したときは、ログインし直さないと変更が反映されません。
sourceコマンドを使うとログインし直さなくても変更が反映されます。

$ source /path/to/.bash_profile

.bash_profile、.bashrc

.bash_profile

PATH=/usr/local/Cellar/git/2.13.3/bin:/usr/local/bin:/usr/local/lib/node_modules/yuidocjs:/usr/local/bin/dot:$PATH
export PATH=$(brew --prefix homebrew/php/php56)/bin:~/.composer/vendor/bin:$PATH
# VAGRANT_HOME を設定
export VAGRANT_HOME=/Volumes/production/s_hiroshi/.vagrant.d
eval "$(rbenv init -)"
source ~/.phpbrew/bashrc
test -r ~/.bashrc && . ~/.bashrc

.bashrc

alias ctags='/usr/local/Cellar/ctags/5.8/bin/ctags'
alias lsa='ls -al'

本当に正しい .bashrc と .bash_profile の使ひ分け - Qiita

export

// input.txt
abc
def
ghi
THIS="LINE is"
export THIS
while read LINE
do
  echo ${THIE} ${LINE}  // 子プロセスで実行。exportしてない変数は使えません。
done < input.txt
LINE is abc
LINE is def
LINE is ghi

変数一覧を表示

$ MYNAME='Hiroshi'
$ set | grep MYNAME

if文

$DB="mysql";
if [[ $DB == "mysql" ]]; then
  mysql -u root myapp_test < ${TRAVIS_BUILD_DIR}/bin/infotownlinkwp.sql;
fi
if [[ $DB == "pgsql" ]]; then 
  psql myapp_test < ${TRAVIS_BUILD_DIR}/bin/infotownlinkwp.sql;
fi

[[]]は言語構造です。対して[はtestの糖衣構文です。

for in

#!/bin/bash
total=0
for x in 100 200 300
do
    total=$(expr $total + $(expr $x \* 2))
done
echo $total
#!/bin/bash
total=0
for x in 100 200 300
do
    total=`expr $total + \`expr $x \* 2\``
done
echo $total

while/read

// input.txt
abc
def
ghi
while read LINE
do
  echo $LINE
done < input.txt

環境構築

env.sh

#!/bin/bash
wget http://rpms.famillecollet.com/enterprise/remi-release-6.rpm
rpm -ivh remi-release-6.rpm
ls /etc/yum.repos.d
yum yum install httpd
yum -y -enablerepo=remi-php70 --disablerepo=amzn-main install php
yum -y --enablerepo=remi-php70 --disablerepo=amzn-main install php-pdo php-mysqlnd php-mbstring
$ chmod o+x env.sh

サンプル集

ディレクトリのファイル一覧を取得

#!/bin/bash
for f in `find . -maxdepth 1 -type f`
do
    echo $f
done

ディレクトリ内のファイルサイズを取得

#!/bin/bash
for f in  `find . -maxdepth 1 -type f`
do
  wc -c < $f
done

ディレクトリサイズ表示

#!/bin/bash
for d in  `find . -maxdepth 1 -type d`
do
  du $d
done

文字列結合

#!/bin/bash

lines=''
while read line
do
   lines=$lines$line 
done < file.txt
echo $lines

file.txt

aaa
bbb
ccc

実行

$ ./script.sh
aaabbbccc

expr

#!/bin/bash
total=0
for x in 100 200 300
do
    total=`expr $total + \`expr $x \* 2\``
done
echo $total

Travis CI

before_script:
  - bash bin/install-wp-tests.sh wordpress_test root '' localhost $WP_VERSION
  - export PATH="$HOME/.composer/vendor/bin:$PATH"
  - |
    if [[ ${TRAVIS_PHP_VERSION:0:2} == "7." ]]; then
      composer global require "phpunit/phpunit=5.7.*"
    else
      composer global require "phpunit/phpunit=4.8.*"
    fi
  - |
    composer global require wp-coding-standards/wpcs
    phpcs --config-set installed_paths $HOME/.composer/vendor/wp-coding-standards/wpcs

script:
  - npm install
  - grunt build
  - phpcs --standard=phpcs.ruleset.xml $(find . -name '*.php')
  - phpunit

after_success: bash ./bin/build-wp.sh

install-wp-tests.sh

#!/usr/bin/env bash

if [ $# -lt 3 ]; then
    echo "usage: $0 <db-name> <db-user> <db-pass> [db-host] [wp-version] [skip-database-creation]"
    exit 1
fi

DB_NAME=$1
DB_USER=$2
DB_PASS=$3
DB_HOST=${4-localhost}
WP_VERSION=${5-latest}
SKIP_DB_CREATE=${6-false}

WP_TESTS_DIR=${WP_TESTS_DIR-/tmp/wordpress-tests-lib}
WP_CORE_DIR=${WP_CORE_DIR-/tmp/wordpress/}

download() {
    if [ `which curl` ]; then
        curl -s "$1" > "$2";
    elif [ `which wget` ]; then
        wget -nv -O "$2" "$1"
    fi
}

if [[ $WP_VERSION =~ [0-9]+\.[0-9]+(\.[0-9]+)? ]]; then
    WP_TESTS_TAG="tags/$WP_VERSION"
elif [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then
    WP_TESTS_TAG="trunk"
else
    # http serves a single offer, whereas https serves multiple. we only want one
    download http://api.wordpress.org/core/version-check/1.7/ /tmp/wp-latest.json
    grep '[0-9]+\.[0-9]+(\.[0-9]+)?' /tmp/wp-latest.json
    LATEST_VERSION=$(grep -o '"version":"[^"]*' /tmp/wp-latest.json | sed 's/"version":"//')
    if [[ -z "$LATEST_VERSION" ]]; then
        echo "Latest WordPress version could not be found"
        exit 1
    fi
    WP_TESTS_TAG="tags/$LATEST_VERSION"
fi

set -ex

install_wp() {

    if [ -d $WP_CORE_DIR ]; then
        return;
    fi

    mkdir -p $WP_CORE_DIR

    if [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then
        mkdir -p /tmp/wordpress-nightly
        download https://wordpress.org/nightly-builds/wordpress-latest.zip  /tmp/wordpress-nightly/wordpress-nightly.zip
        unzip -q /tmp/wordpress-nightly/wordpress-nightly.zip -d /tmp/wordpress-nightly/
        mv /tmp/wordpress-nightly/wordpress/* $WP_CORE_DIR
    else
        if [ $WP_VERSION == 'latest' ]; then
            local ARCHIVE_NAME='latest'
        else
            local ARCHIVE_NAME="wordpress-$WP_VERSION"
        fi
        download https://wordpress.org/${ARCHIVE_NAME}.tar.gz  /tmp/wordpress.tar.gz
        tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR
    fi

    download https://raw.github.com/markoheijnen/wp-mysqli/master/db.php $WP_CORE_DIR/wp-content/db.php
}

install_test_suite() {
    # portable in-place argument for both GNU sed and Mac OSX sed
    if [[ $(uname -s) == 'Darwin' ]]; then
        local ioption='-i .bak'
    else
        local ioption='-i'
    fi

    # set up testing suite if it doesn't yet exist
    if [ ! -d $WP_TESTS_DIR ]; then
        # set up testing suite
        mkdir -p $WP_TESTS_DIR
        svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes
        svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/data/ $WP_TESTS_DIR/data
    fi

    if [ ! -f wp-tests-config.php ]; then
        download https://develop.svn.wordpress.org/${WP_TESTS_TAG}/wp-tests-config-sample.php "$WP_TESTS_DIR"/wp-tests-config.php
        # remove all forward slashes in the end
        WP_CORE_DIR=$(echo $WP_CORE_DIR | sed "s:/\+$::")
        sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR/':" "$WP_TESTS_DIR"/wp-tests-config.php
        sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" "$WP_TESTS_DIR"/wp-tests-config.php
        sed $ioption "s/yourusernamehere/$DB_USER/" "$WP_TESTS_DIR"/wp-tests-config.php
        sed $ioption "s/yourpasswordhere/$DB_PASS/" "$WP_TESTS_DIR"/wp-tests-config.php
        sed $ioption "s|localhost|${DB_HOST}|" "$WP_TESTS_DIR"/wp-tests-config.php
    fi

}

install_db() {

    if [ ${SKIP_DB_CREATE} = "true" ]; then
        return 0
    fi

    # parse DB_HOST for port or socket references
    local PARTS=(${DB_HOST//\:/ })
    local DB_HOSTNAME=${PARTS[0]};
    local DB_SOCK_OR_PORT=${PARTS[1]};
    local EXTRA=""

    if ! [ -z $DB_HOSTNAME ] ; then
        if [ $(echo $DB_SOCK_OR_PORT | grep -e '^[0-9]\{1,\}$') ]; then
            EXTRA=" --host=$DB_HOSTNAME --port=$DB_SOCK_OR_PORT --protocol=tcp"
        elif ! [ -z $DB_SOCK_OR_PORT ] ; then
            EXTRA=" --socket=$DB_SOCK_OR_PORT"
        elif ! [ -z $DB_HOSTNAME ] ; then
            EXTRA=" --host=$DB_HOSTNAME --protocol=tcp"
        fi
    fi

    # create database
    mysqladmin create $DB_NAME --user="$DB_USER"$EXTRA
}

install_wp
install_test_suite
install_db

build-wp.sh

#!/usr/bin/env bash

if [[ "false" != "$TRAVIS_PULL_REQUEST" ]]; then
    echo "Not deploying pull requests."
    exit
fi

if [[ "master" != "$TRAVIS_BRANCH" ]]; then
    echo "Not on the 'master' branch."
    exit
fi

if if [[ ${TRAVIS_PHP_VERSION:0:3} != "5.6" ]]; then
    exit;
fi

cd dev/build

git init
git config user.name "s-hiroshi"
git config user.email "info@info-town.jp"
git add .
git commit --quiet -m "Push from Travis CI"
git push --force --quiet "https://${GH_TOKEN}@${GH_REF}" master:build > /dev/null 2>&1

データベースバックアップ

#!/bin/sh

# バックアップ先ディレクトリ
# BKDIR=/var/www/minker/backup/database/full
BKDIR=/data/minker/backup/database/full

# 本スクリプトパス
MYPATH=$(cd $(dirname $0);pwd)

#世代管理(何日分残すか)
DAYAGO="31"

# MySQユーザー
USER=minker

# MySQL minkerパスワード
PASS=Ma0em1007R

# 日付・時刻取得し変数に代入
TIMESET=`date +%Y%m%d-%H%I%M`

#バックアップ先ファイル名を設定 設定ファイルにあるファイル名+日付.tar.gzする
BKFILE=${BKDIR}/mysql.$TIMESET.tar.gz

# データベース名取得
DBNAME=minker

# DBNAMEデータベースをmysqldumpでバックアップ
# $?は最後に実行したコマンドの戻り値
mysqldump --user=${USER} --password=${PASS} $DBNAME --opt  > ${BKDIR}/$(date "+${DBNAME}-%Y%m%d%H%M%S").sql | logger -t mysqldump
if [ $? = 0 ]; then
  logger -t mysqldump "Backup OK mysqldump:${DBNAME}"
else
# 失敗したらその旨を表示かつ、ログに保存、メール送信
  logger -t mysqldump "Backup NG mysqldump:${DBNAME}"
fi

# yyyymmdd形式のファイルから古い物を削除
# 削除しきい日付(yyyymmdd)を設定。(DAYAGO日前の日付求める)
tday=`date -d "${DAYAGO} day ago" +%Y%m%d`

# 対象Dir配下のファイル名をwhileに渡し「$list」となる
ls $BKDIR|while read list
do
   #ファイル名に「数字x14」が含まれている場合、
   if  expr "$list" : "minker\-[0-9]\{14\}.sql" > /dev/null; then
      # $listから、「yyyymmdd」を取り出しepoch時間($fday)にする
      fday=`expr $list : "minker\-\([0-9]\{8\}\)[0-9]\{6\}.sql"`
      #ファイル名から取得した「yyyymmdd」がDAYAGOの「yyyymmdd」よりも小さいとき削除
      if [ -n "$fday" ] && [ $fday -lt $tday ]; then
         # echo する
         # echo $list
         #削除する
         `sudo rm -f ${BKDIR}/${list}`
      fi
   fi
done