20191130のLinuxに関する記事は4件です。

シェルスクリプトTIPS

シェルスクリプトのTIPS

最近はPyrhonやRubyなど他のスクリプト言語も流行っていますが、Unixエンジニアと言えばシェルスクリプト。この記事は基本的なシェルスクリプトがかける人向けのTIPSです。他人が書いたシェルスクリプト読んでいて、「なんだこれ?」と思った時の参考にして下さい。

◆安全なSHEBANGについて(/bin/shの実体)

昨今、多くのUnixOSの/bin/shはBashとなっているが、実はすべてのUnix/Linuxがそうなっているとは限らない。AshだったりZshだったりDashだったりの可能性もある。なので、BASH固有の機能などを利用しているシェルスクリプトの場合、一行目に書くシェバンは、シェルを明示しておく。

#!/bin/bash

もしくはすべてのUnixシェルで実行できるよう古典的で安全な(PORTABLEな)シェルスクリプトを記述しておくと良い。ただし、実行速度が低下したり、配列が使えない、EXPRコマンドを用いたインクリメントがトリッキーなどの制限がある。

◆DEBUGモード

どこでエラーが起きているのかわからないが正常終了しない場合、Xオプションを付けてDEBUGモードで実行する。シェルプログラミングの場合、これとPRINTFデバッグで大方は解決する。

# /bin/bash -x myscript.sh
◆インクルード

ドットの後にパラメータや自作の関数などを定義したファイルを指定すれば、実行時に読み込まれる。パラメータ専用ファイルなどを作成し、プロジェクトごとに編集すれば直接スクリプトを編集するより安全にカスタマイズ・デプロイが可能となる。

#!/bin/bash

. /usr/dev/param
. /user/dev/functions

#(以下省略)
◆ワンライナー1 セミコロンで複数行を1行に収める
for name in foo bar foo2
do
  echo ${name}
done

セミコロンを用いて一行で書くと次のように表せる

for name in foo bar foo2; do echo ${name}; done

ワンライナーの良い点として可読性は低下するがコマンドラインで気軽に投入が可能で、高度なコマンドを運用マニュアルに組み込むことができる。

◆ワンライナー2 異なる記述で同じ処理をさせる
if [ -e /var/tmp/test ]
then
   rm /var/tmp/test
fi

前のコマンドが正常終了(終了コードはTrue)した場合、&& 以降の処理を実行する。
頻出の記述法なので知っておくと〇

[ -e /var/tmp/test ] && rm /var/tmp/file 

よく知られた話だが if [ ] then ~ の [ は、実体は /bin/test のエイリアス(別名)である /bin/[ であり、次のように記述することができる

/bin/test -e /var/tmp/test && rm /var/tmp/file

&&と逆で、直前のコマンドが異常終了(終了コードがTrueでない)した場合、|| 以降の処理を実行する。
[ の後の ! はNOTを意味し、ファイルが存在しない場合を表す。

# testファイルが存在しない場合、作成しなさい
if [ ! -e /var/tmp/test ]
then
   touch /var/tmp/test
fi

下のように書くことが可能。

[ -e /var/tmp/test ] || touch /var/tmp/test
◆&&と||を利用したワンライナーのハマりポイント

よくやる間違いで下記のコードは意味が異なるので注意する。
test_Aが成立している場合、コマンドBを実行し、そうでない場合はコマンドCを実行する

If [ test_A ]
then
  command_B
else
  command_C
fi
[ test_A ] && command_B || command_C

上記ではtest_Aが成立している場合、コマンドBを実行する、そうでない場合は、コマンドCを実行する。ところが、test_Aが成立しておりコマンドBの実行した後、コマンドBの実行結果が失敗だった場合はコマンドCが実行されてしまう (ココがハマリポイント)

◆逆ワンライナー 1行で書ける処理を複数行に分割する

スクリプトの可読性を高める場合に利用される。

cat /var/tmp/test.log | grep -v ^# | sed -^#/d | egrep 'foo1|foo4|foo5' | awk '{print $1,$3,$7,$11}' | sort -e | sed -e 's/foo/bar/g' > /var/tmp/tmp.log.txt
cat /var/tmp/test.log              | \
    grep -v ^#                     | \
    sed -e '^$/d'                  | \
    egrep 'foo1|foo4|foo5'         | \
    awk '{print $1,$3,$7,$11}'     | \ 
    sort -u                        | \
    sed -e 's/foo/bar/g'             \
    > /var/tmp/tmp.log.txt
◆[ と [[ の違い

シェルスクリプトでは正規表現と組み合わせて[[がパターンマッチングで利用されます。
クォートしていない場合、パターンマッチングの結果、fooはfo[ou](fooもしくはfouのどちらか)に該当するためTrueが返されます。
ただし、[[でもクォートしている場合、文字列解釈の結果は変わらないためFalseが返されます。

# 文字列はアンマッチ
(bash)# [ qiita == 'qiit[aiueo]' ]; echo $?
1

# 文字列はマッチ
(bash)# [[ qiita == qiit[aiueo] ]]; echo $?
0

# 文字列はアンマッチ
(bash)# [[ qiita == 'qiit[aiueo]' ]]; echo $?
1

その他に大きな違いとしては、文字列のパターンマッチングに利用される他、[[の場合、文字列に数式が書かれている場合は文字列と解釈せず、計算を行ってからテストが実行される。こちらも覚えておくと◎。

(bash)# char='10 + 10'
(bash)# [ ${char} -eq 20 ]; echo $?
-bash: [: 10+10 integer expression expected

(bash)# [[ ${char} -eq 20 ]]; echo $?
0
◆インクリメント・デクリメント

外部コマンド expr を用いて計算。exprのプロセスをforkするコストが高いためスクリプトの実行速度はやや遅くなるが、どのUnixシェルでも動作するため安全でポータブル性が高い書き方となる。

cnt=`expr ${cnt} + 1`
cnt=`expr ${cnt} - 1`

BASHのビルドイン機能。以下の3つの書き方だと実行結果は高速だが、他のシェルで動かない場合もあるため、BASHの脆弱性が見つかった場合などに他のシェルに切り替えて実行するなどの対策は打てなくなるというデメリットがある。

((cnt++))
let cnt++
let ++cnt
※デクリメントは--にしてください 
◆ユーザによる入力を受け付ける

ITやCASEを利用してユーザによる値の入力や選択を記述できる。入力文字列を表示させたくない場合はSオプションを利用する。

(bash)# read str
aiueo <ENTER>
(bash)# echo ${str}
aiueo
◆分岐先で何もしたくない時はコロン

if elseやcaseにいろいろ分岐を書いていたけれど、いくつかの処理をとりやめたい場合でも、後に再度利用しそうだったり、条件式やパラメータなどが非常に重要で消したくなかったりする場合、その分岐構造そのものは残しておきたかったりする場合があります。そういう場合は処理部をコメントアウトし替わりに : を入れておきます。

if [ -e /usr/dev/functions ] 
then
      . /usr/dev/functions
else
      # (停止したい処理はコメントアウト)
      :
fi
◆yesコマンド

文字列yと終了コード0を超高速で延々と返す謎のコマンドyes。

(bash)# yes
y
y
y
y

使う場面が思い浮かばないと思いきや、無限ループさせたい場合に使ったりします。

#!/bin/bash

. /usr/dev/functions
. /usr/dev/param

while [ yes ]
do
   sleep ${interval}
   chk=$(ps -ef | grep -c ${srvs})
   if [ ${chk} -lt 2 ] 
   then
      # function alert_to
      aleat_to all_engineer@foobar.co.jp
      # function reboot_services
      reboot_services ${srvs}
   fi
done

◆スクリプトの簡単なDaemon化

常駐化させてデーモン化(サービス化)させたい場合なんかにはnohupを使います。以下のスクリプトですと、process_chk.shはログアウト後も常駐プロセスとなり働き続けてくれます。

(bash)# nohup /bin/bash process_chk.sh &
◆スクリプトの実行結果を画面でも見たいし、同時にファイルにも保存したい
(bash)# ./chk.sh | tee -a /var/tmp/result.log
OK
OK
NG
◆精密な計算を行いたい

exprコマンドは整数しか扱えないため、小数点何桁といった計算を行うにはbcコマンドを利用する。デフォルトでは小数点以下は表示しないので、scaleで桁数を指定する。

#!/bin/bash
result=$(echo "scale=1; 101354 * 1.08" | bc)
echo ${result}
◆ランダムな数値を得る

BASHのシェル変数を利用するパターン

(bash)# echo ${RANDOM}
8732

BASHの機能を利用せず安全でポータブルな方法を検討した結果、時間の文字列でハッシュをとれば良いんじゃないかというアイデアが上手くいった

(bash)# date | md5sum | tr -dc "0123456789"
87329348
◆ランダムな文字列を得る

先ほどの手法を再利用して、ランダムな文字列を得る。シンプルな出し方のため、パスワードとして利用するには向かない。パスワードとして利用するにはdateコマンドのオプションを工夫するか、次の方法を利用する。

(bash)# date | md5sum | tr -dc "abcdefghijklmnopqrstuvwxyz"
ndrtnrvlkjr
◆暗号強度の高い文字列を得る

先ほどの手法で任意のパスワードなどを生成することができるが、パスワードとして利用するには類推可能であるため、ここで得た文字列にもう少し高度な処理を施しておくと、事前計算による類推や一覧表からの抽出は使えなくなりより強度が増します。具体的にはパスワードソルトを指定しておきます。

(bash)# SALT=hogehoge
(bash)# echo "$(date)${SALT}" | md5sum | tr -dc "abcdefghijklmnopqrstuvwxyz"
fdsjlnelr
◆typesetとdeclare

どちらも同じ変数を宣言する命令。typedefはKSHなど他のシェルでも利用が可能で古典的かつポータブル。declaireの方が新しい。

オプション 内容
a 配列を宣言
i 数値を宣言
r 読み出し専用を宣言
p 宣言した変数の値を表示

他にもあれば適当に更新の予定。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[linux] デフォルトアプリの設定変更

デフォルトのファイルマネージャー等が実行できない(Failed to exucute child process ) とエラーが出たときの対処法となります。

windowsでいう「既定のアプリを設定する」は、linuxでは「設定マネージャー」→「お気に入りのアプリケーション」から変更できます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【AWS】EC2インスタンスでswapサイズを増やす手順

EC2インスタンスでswapサイズを増やす手順

PostgreSQLを使って処理を回していたらあるときからOOMキラーが発動するようになった。
単純にはインスタンスタイプを上げてメモリを増やせば解決するけど、それだと費用は倍になるし、オーバースペックになる。
ふと思ってswapサイズを見てみたら「0.8GBしかないじゃん!?」となったのでswapサイズを増やすことにした。
なお、今回はパーティションを増やしたくないため拡張で対応しているが、新しくパーティションを切る方法もある。

事前準備

下記の図のようにswapサイズをデフォルトの0.8GBから30GB拡張する。
swap拡張.png
ルートボリュームを30GB拡張、ファイルシステム拡張、LVM拡張、swap拡張、というように下から順にやれば良い。
初期状態のルートボリューム30GBではこのような状態になっている。

[root@apple ~]# lsblk
NAME                       MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
xvda                       202:0    0   30G  0 disk
├xvda1                     202:1    0  500M  0 part /boot
├xvda2                     202:2    0  7.5G  0 part
│├VolGroup-lv_root (dm-0)  253:0    0 26.7G  0 lvm  /
│└VolGroup-lv_swap (dm-1)  253:1    0  816M  0 lvm  [SWAP]
└xvda3                     202:3    0   22G  0 part
  └VolGroup-lv_root (dm-0) 253:0    0 26.7G  0 lvm  /

AWSコンソールからルートボリュームのサイズを30GBから60GBに増やすと /dev/xvda が60GBに増える。

[root@apple ~]# lsblk
NAME                       MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
xvda                       202:0    0   60G  0 disk
├xvda1                     202:1    0  500M  0 part /boot
├xvda2                     202:2    0  7.5G  0 part
│├VolGroup-lv_root (dm-0)  253:0    0 26.7G  0 lvm  /
│└VolGroup-lv_swap (dm-1)  253:1    0  816M  0 lvm  [SWAP]
└xvda3                     202:3    0   22G  0 part
  └VolGroup-lv_root (dm-0) 253:0    0 26.7G  0 lvm  /

パーティション、ファイルシステムを拡張する

/dev/xvda が30GB増えたので、パーティション /dev/xvda3 を30GB増やしたい。
パーティション拡張にはgrowpartコマンドを使用する。

# growpartインストール
[root@apple ~]# yum install growpart

# epelにあるが、ファイルがNot Foundとか言われたらパスが変わっているかもしれない
# そういうときはパスを確認してwgetで取ってくれば良い
[root@apple ~]# wget ~~~/cloud-utils-growpart-0.27-10.el6.x86_64.rpm
[root@apple ~]# rpm -ivh cloud-utils-growpart-0.27-10.el6.x86_64.rpm

# ロケールが "en_US.UTF-8" じゃないと失敗するのでロケール変更
[root@apple ~]# export LC_ALL="en_US.UTF-8"

# growpart実行
# パーティション番号はスペースを空ける
[root@apple ~]# growpart /dev/xvda 3
CHANGED: partition=3 start=16777216 old: size=46133324 end=62910540 new: size=109043864,end=125821080

# オンラインでのresize2fsはできないので再起動する
# 起動時に自動的にresize2fsしてくれる
[root@apple ~]# reboot

# パーティション拡張を確認
[root@apple ~]# lsblk
NAME                       MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
xvda                       202:0    0   60G  0 disk
├xvda1                     202:1    0  500M  0 part /boot
├xvda2                     202:2    0  7.5G  0 part
│├VolGroup-lv_root (dm-0)  253:0    0 26.7G  0 lvm  /
│└VolGroup-lv_swap (dm-1)  253:1    0  816M  0 lvm  [SWAP]
└xvda3                     202:3    0   52G  0 part
  └VolGroup-lv_root (dm-0) 253:0    0 26.7G  0 lvm  /

/dev/xvda3 が22GBから52GBに増えているのでヨシ!

LVMを拡張する

パーティションのサイズが増えたのでまずPV、VGを拡張する。

# 拡張前
[root@apple ~]# pvdisplay /dev/xvda3
  --- Physical volume ---
  PV Name               /dev/xvda3
  VG Name               VolGroup
  PV Size               22.00 GiB / not usable 2.04 MiB
  Allocatable           yes
  PE Size               4.00 MiB
  Total PE              5631
  Free PE               511
  Allocated PE          5120
  PV UUID               XAzVVN-F4vG-XWcq-Ay61-4v2A-Hynk-hcmKja

# PV拡張
[root@apple ~]# pvresize /dev/xvda3
  Physical volume "/dev/xvda3" changed
  1 physical volume(s) resized / 0 physical volume(s) not resized

# 拡張後
[root@apple ~]# pvdisplay /dev/xvda3
  --- Physical volume ---
  PV Name               /dev/xvda3
  VG Name               VolGroup
  PV Size               52.00 GiB / not usable 3.07 MiB
  Allocatable           yes
  PE Size               4.00 MiB
  Total PE              13310
  Free PE               8190
  Allocated PE          5120
  PV UUID               XAzVVN-F4vG-XWcq-Ay61-4v2A-Hynk-hcmKja

# VG確認
[root@apple ~]# vgdisplay
  --- Volume group ---
  VG Name               VolGroup
  System ID
  Format                lvm2
  Metadata Areas        2
  Metadata Sequence No  6
  VG Access             read/write
  VG Status             resizable
  MAX LV                0
  Cur LV                2
  Open LV               2
  Max PV                0
  Cur PV                2
  Act PV                2
  VG Size               59.50 GiB
  PE Size               4.00 MiB
  Total PE              15232
  Alloc PE / Size       7042 / 27.51 GiB
  Free  PE / Size       8190 / 31.99 GiB
  VG UUID               KKH8X5-ZgIG-drSY-yYeX-znc7-APSq-kCVFJm

PV Size、Free PEともに30GB増えている。
またVGはPVの拡張にともなって自動的にVG Size、Free PEが増えている。

swapサイズを拡張する

最後にswapが乗っているLV、およびswapサイズを拡張する。

# LV確認
[root@apple ~]# lvdisplay
  --- Logical volume ---
  LV Path                /dev/VolGroup/lv_root
  LV Name                lv_root
  VG Name                VolGroup
  LV UUID                xL8jFY-tYoP-Akp8-wiLV-PbUm-5YdW-jc7kTQ
  LV Write Access        read/write
  LV Creation host, time localhost.localdomain, 2014-08-20 14:05:30 +0900
  LV Status              available
  # open                 1
  LV Size                26.71 GiB
  Current LE             6838
  Segments               2
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     256
  Block device           253:0

  --- Logical volume ---
  LV Path                /dev/VolGroup/lv_swap
  LV Name                lv_swap
  VG Name                VolGroup
  LV UUID                0hYwIt-mA9J-Mfhw-x9fc-jmRd-520Q-OMLhQ0
  LV Write Access        read/write
  LV Creation host, time localhost.localdomain, 2014-08-20 14:05:32 +0900
  LV Status              available
  # open                 1
  LV Size                816.00 MiB
  Current LE             204
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     256
  Block device           253:1

# swapサイズ確認(現在0.8GB)
[root@apple ~]# swapon -s
Filename                                Type            Size    Used    Priority
/dev/dm-1                               partition       835580  0       -1

# いったんswapを無効化
[root@apple ~]# swapoff /dev/VolGroup/lv_swap

# LV拡張
[root@apple ~]# lvextend -L+30G /dev/VolGroup/lv_swap
  Extending logical volume lv_swap to 30.80 GiB
  Logical volume lv_swap successfully resized

# swapの再作成、再有効化
[root@apple ~]# mkswap /dev/VolGroup/lv_swap
mkswap: /dev/VolGroup/lv_swap: warning: dont erase bootbits sectors
        on whole disk. Use -f to force.
スワップ空間バージョン1を設定します、サイズ = 32292860 KiB
ラベルはありません, UUID=81ef3a01-380d-4305-bf2f-bdb7bdac39bf

[root@apple ~]# swapon /dev/VolGroup/lv_swap

# swapサイズ再確認(30GB増えている)
[root@apple ~]# swapon -s
Filename                                Type            Size    Used    Priority
/dev/dm-1                               partition       32292860        0       -1

swapサイズは無事拡張されたが、このあと /etc/fstab を修正する必要がある。
/etc/fstab には /、/boot、swap がそれぞれUUIDで記載されているが、mkswapしたときに値が変わっているのである。

[root@apple ~]# vi /etc/fstab
UUID=d748f0cb-bf25-402c-9a58-3f6dd4a3b5d7       /               ext4    defaults        1 1
UUID=833e1f14-6c25-4430-8776-d4ad024ee760       /boot           ext4    defaults        1 2
UUID=9c8c7b9c-a4d6-4217-a498-5816b5e7e00b       swap            swap    defaults        0 0
tmpfs                                           /dev/shm        tmpfs   defaults        0 0
devpts                                          /dev/pts        devpts  gid=5,mode=620  0 0
sysfs                                           /sys            sysfs   defaults        0 0
proc                                            /proc           proc    defaults        0 0

# UUIDをパーティションに直すと下記のようになる

/dev/mapper/VolGroup-lv_root    /               ext4    defaults        1 1
/dev/xvda1                      /boot           ext4    defaults        1 2
/dev/VolGroup/lv_swap           swap            swap    defaults        0 0
tmpfs                           /dev/shm        tmpfs   defaults        0 0
devpts                          /dev/pts        devpts  gid=5,mode=620  0 0
sysfs                           /sys            sysfs   defaults        0 0
proc                            /proc           proc    defaults        0 0

以上。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

git pull したら permission deniedになったから、その解決法をメモ

開発環境用のサーバーで、git pull したら、
permission denied でエラーになった。

まさしくこのような感じのエラー

$ git pull
error: cannot open ファイル名: Permission denied

エラーの原因としては、自分が使用しているユーザーはそのディレクトリを変更する権限を持っていないからが理由のよう。

試しにファイルの権限を確認

$ ll
-rw-r--r--   1 hoge  hoge   5742 10 26  2018 test1.php
-rw-r--r--@  1 fuga  hoge   6807 10 12  2018 test2.php
-rw-r--r--   1 hoge  hoge     65 10 11  2018 a1.php
-rw-r--r--   1 fuga  hoge     65 10 11  2018 a2.php

本来であれば、hogeユーザーで作業する決まりだが、
fugaユーザーで作業した人がいたみたい。。

なら、ファイルの権限を変更すればOKと思いきや、
修正するファイルは、プロジェクトのいたるところにあり、
おまけに.git配下も修正しなくてはいけず、いちいち該当するファイルのパスを指定して権限を変更していたら日が暮れるという感じ。。

まとめてファイルの権限を変更

ということで、便利なlinuxコマンドもメモしておく

ルートディレクトリで作業

//ファイル
find ./ -user fuga -type f -print | sudo xargs chown hoge:hoge

// ディレクトリ
find ./ -user fuga -type d -print | sudo xargs chown hoge:hoge

//シンボリックリンク
find ./ -user fuga -type l -print | sudo xargs chown hoge:hoge

これでまとめて権限を変更することが可能。

実行する流れとしては、

find ./ -user fuga -type f -print

で該当するファイル一覧を確認し

find ./ -user fuga -type f -print | sudo xargs chown hoge:hoge

で権限をまとめて変更

find ./ -user fuga -type f -print

再び、こちらを実行し、ファイルが表示されないことを確認って感じ。

こういうコマンドをすらすら思いつけるようになりたい。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む