Quantcast
Channel: Linux –俺的備忘録 〜なんかいろいろ〜
Viewing all 743 articles
Browse latest View live

シェルスクリプトで指定した月の第何何曜日を取得する

$
0
0

いい感じで家でお酒飲んでて、ゴミ出しの日を意識してふと思い立ち、指定した日の第何何曜日(第3水曜とか、第4金曜とか…)をbashで取得出来ないかなと思ったのでやってみた。
ncalとかあると一行で取得出来そうだったけど、手元のCentOS 7だと入ってなかったのでそれを使わずに出来ないか調べた。

で、dateコマンドのみでで上手く出せれば良かったんだけど、少し目論見が外れてしまった。
「-d」で月初日と次の曜日を同時に指定できればよかったんだけど…

20151127_000000

[root@test-centos7 ~]# date
2015年 11月 27日 金曜日 00:20:52 JST
[root@test-centos7 ~]#
[root@test-centos7 ~]# date -d '1 monday'
2015年 11月 30日 月曜日 00:00:00 JST
[root@test-centos7 ~]#
[root@test-centos7 ~]# date -d '2 monday'
2015年 12月  7日 月曜日 00:00:00 JST
[root@test-centos7 ~]#
[root@test-centos7 ~]# date -d '2015/11/01 1 monday'
2015年 11月  1日 日曜日 00:00:00 JST
[root@test-centos7 ~]#
[root@test-centos7 ~]# date -d '1 monday 2015/11/01'
2015年 11月  1日 日曜日 00:00:00 JST
[root@test-centos7 ~]#
[root@test-centos7 ~]# date -d '2015/11/01' -d '1 monday'
2015年 11月 30日 月曜日 00:00:00 JST

とまぁ、こんな感じで思ったようには動かなかった。
なお、dateコマンドをネストしても動きは変わらずなので、dateコマンドのみでは上手くいかなそうだ。残念。

ううん、phpならstrtotimeで一発なんだけどなぁ…同じように指定すればいいかと思ったけど、そう甘くはない。
pythonにもこの辺の関数は無いっぽい…

【参考:2015年12月の第2月曜日をphpで取得する】

php -r 'echo date("Y/m/d\n", strtotime("Second Monday of Dec 2015"));'
[root@test-centos7 ~]# php -r 'echo date("Y/m/d\n", strtotime("Second Monday of Dec 2015"));'
2015/12/14

しょうがないので、大分出来が悪いけどやっつけでシェルスクリプトを組んでみることにした。
(使うことがあるのか不明だが)

●get_weekday_of_month.sh

base="$1/01"
base_dayofweek=$( date -d $base +%w )
# 0=Sun,1=Mon,2=Tue,3=Wed,4=Thu,5=Fri,6=Sat
target_dayofweek=$2
week_no=$3

if [ $base_dayofweek="0" ]; then
    date -d "$base + $(( (7 - base_dayofweek + target_dayofweek) % 7 + 7*($week_no-1))) days"
else
    date -d "$base + $(( (7 - base_dayofweek + target_dayofweek) % 7 - 1 + 7*($week_no-1))) days"
fi

20151127_000001

[root@test-centos7 ~]# cat /work/get_weekday_of_month.sh
base="$1/01"
base_dayofweek=$( date -d $base +%w )
# 0=Sun,1=Mon,2=Tue,3=Wed,4=Thu,5=Fri,6=Sat
target_dayofweek=$2
week_no=$3

if [ $base_dayofweek="0" ]; then
    date -d "$base + $(( (7 - base_dayofweek + target_dayofweek) % 7 + 7*($week_no-1))) days"
else
    date -d "$base + $(( (7 - base_dayofweek + target_dayofweek) % 7 - 1 + 7*($week_no-1))) days"
fi
#date -d "$base + $(( (7 - base_dayofweek + target_dayofweek) % 7 )) days"

[root@test-centos7 ~]#
[root@test-centos7 ~]# sh /work/get_weekday_of_month.sh 2015/12 1 2
2015年 12月 14日 月曜日 00:00:00 JST
[root@test-centos7 ~]#
[root@test-centos7 ~]# sh /work/get_weekday_of_month.sh 2015/10 1 2
2015年 10月 12日 月曜日 00:00:00 JST
[root@test-centos7 ~]#
[root@test-centos7 ~]# sh /work/get_weekday_of_month.sh 2015/10 3 2
2015年 10月 14日 水曜日 00:00:00 JST

 

…そもそも、書いてて思ったんだけどスクリプトでその辺の日程を取得する意味があったんだろうか?
使う事あるのだろうか?ゴミの日くらいしか思いつかない…

 

シェルプログラミング実用テクニック (Software Design plus) シェルプログラミング実用テクニック (Software Design plus)

dateutilsを使って簡単に指定月の第何何曜日を取得する

$
0
0

先ほど、指定月の第何何曜日を取得するスクリプトを作成したのだが、もうちょっといいツールが無いか探して見たところ、dateutilsというものを見つけた。
これのdateconvを使えば、かなり簡単に指定曜日の日付を取得出来そうだ。

1.インストール

インストールは、RHEL系だとコンパイルが必要のようだ。
以下のコマンドを実行する。

wget https://bitbucket.org/hroptatyr/dateutils/downloads/dateutils-0.3.4.tar.xz
tar xvf dateutils-0.3.4.tar.xz
cd dateutils-0.3.4
./configure
make
make install

 

Ubuntuの場合、apt-getでインストールできる。

sudo apt-get install dateutils

これでインストールが完了する。

2.コマンドの実行

さて、それでは早速コマンドを実行してみよう。
以下のように実行する事で、指定した月の第何何曜日を取得できる。

dateconv YYYY-MM-何週目か-曜日 -i "%Y-%m-%c-%a" -f '%Y/%m/%d'

20151127_000002

[root@test-centos7 ~]# dateconv 2015-01-03-Mon -i "%Y-%m-%c-%a" -f '%Y/%m/%d'
2015/01/19
[root@test-centos7 ~]# cal 01 2015
      1月 2015
日 月 火 水 木 金 土
             1  2  3
 4  5  6  7  8  9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31

[root@test-centos7 ~]#
[root@test-centos7 ~]# dateconv 2015-11-03-Mon -i "%Y-%m-%c-%a" -f '%Y/%m/%d'
2015/11/16
[root@test-centos7 ~]# cal 11 2015
      11月 2015
日 月 火 水 木 金 土
 1  2  3  4  5  6  7
 8  9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30

 

お~、こりゃ楽だわ。
他にも色々なツールがあるみたいだし、うまく使いこなせれば何かできるかも。。。

JP1によるジョブ管理の実践ノウハウ 第2版 JP1によるジョブ管理の実践ノウハウ 第2版

cronで第何何曜日にスクリプトを実行するか指定する

$
0
0

シェルスクリプトで第何何曜日を取得する方法について調べてたので、今度はcronで、毎月決まった週の曜日にだけスクリプトを実行させるような指定方法がないか調べてみることにした。
で、調べてみると、どうやら日の範囲と曜日はandではなくor指定になっているようで、以下のように指定すると「指定曜日もしくは指定範囲日の場合はコマンド実行」となってしまう。

# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed
# 第一月曜日の深夜3時にコマンドを実行させたい(が、この指定だと毎月1~7日もしくは月曜日にコマンドが実行される)
0 3 1-7 * 1 ユーザ コマンド

で、これを回避するには、以下のようにコマンド実行側で曜日を識別させることで『何週目の何曜日にスクリプトを実行させる』事は可能だ。

# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed
# * * 範囲を指定 * * ユーザ [ $(date "+\%w") -eq 曜日 ] && コマンド

# 第1月曜の深夜3時にコマンド実行
0 3 1-7 * * root [ $(date "+\%w") -eq 1 ] && コマンド

# 第2水曜の深夜3時に以下略
0 3 8-14 * * root [ $(date "+\%w") -eq 3 ] && コマンド

# 第3木曜の以下略
0 3 15-21 * * root [ $(date "+\%w") -eq 4 ] && コマンド

# 第4日曜の以下略
0 3 22-28 * * root [ $(date "+\%w") -eq 0 ] && コマンド

 

結局、指定範囲内には必ず第何曜日が来るわけなので、日付をその範囲で指定した上で曜日を指定してあげればいいだけなんだよね。
なお、曜日ではなく月末にコマンドを実行させたい場合は、以下のように『月末になりうる日』に当日が月末かどうかを判定させて、月末であればコマンドをキックさせるようにすればいい。

0 3 28-31 * * root [ $(date "+\%d" -d "+1day") -eq 1 ] && コマンド

 

とりあえず、これで第何何曜日にスクリプトが実行されるように指定することが出来る。

【参考】 http://blog.livedoor.jp/blackwingcat/archives/1029569.html

 

2週間でできる! スクリプト言語の作り方 (Software Design plus) 2週間でできる! スクリプト言語の作り方 (Software Design plus)

dateコマンドで現在時刻を騙す『libfaketime』

$
0
0

dateコマンドでは、「-d」で○○日後とか、□月後といった指定で日付を取得することが出来る。
しかし、特定の日付を指定した上で○○日後の日付を指定する事が出来ない。

もしdateコマンドで特定の日付の○○日後、次の○曜日といった指定をする場合、今回紹介する『libfaketime』を用いると便利だろう。
これは、dateコマンドが読み込む現在日時を変数「FAKETIME」とすることで、システム時刻に変更を加える事なく特定の日付をdateコマンドで出力させることが出来る。

1.インストール

まずはインストール。
以下コマンドを実行し、コンパイル・インストールを行う。

git clone https://github.com/wolfcw/libfaketime
cd libfaketime/
make
make install

2.日時を出力させる

次に、実際にどう使うのかについて記述する。
以下のように、インストールしたライブラリ「libfaketime.so.1」をLD_PRELOADに代入し、dateコマンド実行と同時に変数「FAKETIME」に特定の日時を入れるだけだ。

export LD_PRELOAD=/usr/local/lib/faketime/libfaketime.so.1
FAKETIME='特定の日時' date

20151130_000000

[root@test-centos7 libfaketime]# date
2015年 11月 30日 月曜日 22:15:44 JST
[root@test-centos7 libfaketime]#
[root@test-centos7 libfaketime]# date -d 'next sunday'
2015年 12月  6日 日曜日 00:00:00 JST
[root@test-centos7 libfaketime]#
[root@test-centos7 libfaketime]# export LD_PRELOAD=/usr/local/lib/faketime/libfaketime.so.1
[root@test-centos7 libfaketime]# FAKETIME='2015-01-01 00:00:00' date
2015年  1月  1日 木曜日 00:00:00 JST
[root@test-centos7 libfaketime]#
[root@test-centos7 libfaketime]# FAKETIME='2015-01-01 00:00:00' date -d 'next sunday'
2015年  1月  4日 日曜日 00:00:00 JST

 

まぁ、あまり使うことはないような気もするけれどどこかで役に立ちそうな気がしなくもない。

Linuxだからできること200(日経BPパソコンベストムック) Linuxだからできること200(日経BPパソコンベストムック)

bashのsetコマンドで覚えておきたい使い方9個

$
0
0

シェルスクリプトを作る上で、以外と便利なのがsetコマンド。
オプションごとに関連性が薄いので覚えにくいのだが、使いこなせれば結構役に立つ事が多いコマンドだ。

今回は、そんなsetコマンドで覚えておきたい使い方についてを紹介する。

1.引数・オプションなしで実行(変数の一覧を表示する)

setコマンドは、引数無しで実行すると現在設定されている変数の一覧を表示させることが出来る。

set

20151201_000003

[root@test-centos7 ~]# set
BASH=/bin/bash
BASHOPTS=checkwinsize:cmdhist:expand_aliases:extquote:force_fignore:histappend:hostcomplete:interactive_comments:login_shell:progcomp:promptvars:sourcepath
BASH_ALIASES=()
BASH_ARGC=()
BASH_ARGV=()
BASH_CMDS=()
BASH_LINENO=()
BASH_SOURCE=()
BASH_VERSINFO=([0]="4" [1]="2" [2]="45" [3]="1" [4]="release" [5]="x86_64-redhat-linux-gnu")
BASH_VERSION='4.2.45(1)-release'
COLUMNS=112
DIRSTACK=()
EUID=0
GROUPS=()
HISTCONTROL=ignoredups
HISTFILE=/root/.bash_history
HISTFILESIZE=1000
HISTSIZE=1000
HOME=/root
HOSTNAME=test-centos7
HOSTTYPE=x86_64
ID=0
IFS=$' \t\n'
LANG=ja_JP.UTF-8
LESSOPEN='||/usr/bin/lesspipe.sh %s'
LINES=36
LOGNAME=root
LS_COLORS='rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:'
MACHTYPE=x86_64-redhat-linux-gnu
MAIL=/var/spool/mail/root
MAILCHECK=60
OPTERR=1
OPTIND=1
OSTYPE=linux-gnu
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/bin:/root/bin
PIPESTATUS=([0]="0")
PPID=23637
PROMPT_COMMAND='printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"'
PS1='[\u@\h \W]\$ '
PS2='> '
PS4='+ '
PWD=/root
SELINUX_LEVEL_REQUESTED=
SELINUX_ROLE_REQUESTED=
SELINUX_USE_CURRENT_RANGE=
SHELL=/bin/bash
SHELLOPTS=braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor
SHLVL=1
SSH_CLIENT='XXX.XXX.XXX.XXX 52074 22'
SSH_CONNECTION='XXX.XXX.XXX.XXX 52074 YYY.YYY.YYY.YYY 22'
SSH_TTY=/dev/pts/0
TERM=xterm
UID=0
USER=root
XDG_RUNTIME_DIR=/run/user/0
XDG_SESSION_ID=8459
_=PATH
colors=/root/.dircolors
[root@test-centos7 ~]#
[root@test-centos7 ~]# set | grep TEST
[root@test-centos7 ~]# TEST=1234
[root@test-centos7 ~]# set | grep TEST
TEST=1234

 

2.実行するコマンドをコンソール上に出力する

「set -v」で実行するコマンドを、「set -x」でそのコマンドの変数等を展開した状態でコンソール上に表示させることが出来る。
(以下例の「printf ~」というのはPS1の表示を行っているもの)

20151201_000005

[root@test-centos7 ~]# echo $HOME
/root
[root@test-centos7 ~]#
[root@test-centos7 ~]# set -v
printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"
[root@test-centos7 ~]# echo $HOME
echo $HOME
/root
printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"
[root@test-centos7 ~]# set +v
set +v
[root@test-centos7 ~]#
[root@test-centos7 ~]# set -x
++ printf '\033]0;%s@%s:%s\007' root test-centos7 '~'
[root@test-centos7 ~]# echo $HOME
+ echo /root
/root
++ printf '\033]0;%s@%s:%s\007' root test-centos7 '~'
[root@test-centos7 ~]# set +x
+ set +x

 

ちなみに、無効にする際はオプション値を「+」を使って記述してあげると良い。

 

3.シェルスクリプトの構文チェックだけを行わせる

シェルスクリプト内に「set -n」もしくは「set -o noexec」を記述することで、スクリプト実行時に構文チェックだけ行わせて、その中の処理を実行させないようにすることが出来る。
例えば、以下のように「set -n」を記述していないスクリプトを実行するとコマンドが実行されてしまうが、記述しているスクリプトだと構文チェックだけを行ってくれている。

20151201_000004

[root@test-centos7 ~]# ls /tmp/test
[root@test-centos7 ~]# cat /work/test27.sh
#!/bin/bash
#set -n
mkdir "/tmp/test/test1234"
for fichier in `ls`
do
    if [[ -f "$fichier ]]; then
          echo "$fichier"
    fi
done
[root@test-centos7 ~]# cat /work/test28.sh
#!/bin/bash
set -n
mkdir "/tmp/test/test5678"
for fichier in `ls`
do
    if [[ -f "$fichier ]]; then
          echo "$fichier"
    fi
done
[root@test-centos7 ~]# bash /work/test27.sh
/work/test27.sh: 行 7: 一致する `"' を探索中に予期しないファイル終了 (EOF) です
/work/test27.sh: 行 10: 条件単項演算子に予期しない引数です
/work/test27.sh: 行 10: 構文エラー: 予期しないファイル終了 (EOF) です
[root@test-centos7 ~]# bash /work/test28.sh
/work/test28.sh: 行 7: 一致する `"' を探索中に予期しないファイル終了 (EOF) です
/work/test28.sh: 行 10: 条件単項演算子に予期しない引数です
/work/test28.sh: 行 10: 構文エラー: 予期しないファイル終了 (EOF) です
[root@test-centos7 ~]# ls /tmp/test
test1234

4.シェルスクリプト内で実行された処理が正常終了しない場合、処理を停止させる

シェルスクリプト内で「set -e」もしくは「set -o errexit」と記述することで、一部の処理を除いて、スクリプト内の実行コマンドが正常終了しなかった場合にスクリプトを即終了させる事が出来る。
例えば、以下の例の場合だと「set -e」が無いとエラーになった後の処理も実行されてしまうが、「set -e」が記述されていればそこで処理が止まっている。

20151202_000000

[root@test-centos7 ~]# ls -la /tmp/TEST
ls: /tmp/TEST にアクセスできません: そのようなファイルやディレクトリはありません
[root@test-centos7 ~]# cat /work/test29.sh
#!/bin/bash
#set -e
mkdir /tmp/TEST1234/TEST
mkdir /tmp/TEST1234/TEST/1234
mkdir /tmp/TEST1234/TEST/5678
[root@test-centos7 ~]# cat /work/test30.sh
#!/bin/bash
set -e
mkdir /tmp/TEST1234/TEST
mkdir /tmp/TEST1234/TEST/1234
mkdir /tmp/TEST1234/TEST/5678
[root@test-centos7 ~]#
[root@test-centos7 ~]# bash /work/test29.sh
mkdir: ディレクトリ `/tmp/TEST1234/TEST' を作成できません: そのようなファイルやディレクトリはありません
mkdir: ディレクトリ `/tmp/TEST1234/TEST/1234' を作成できません: そのようなファイルやディレクトリはありません
mkdir: ディレクトリ `/tmp/TEST1234/TEST/5678' を作成できません: そのようなファイルやディレクトリはありません
[root@test-centos7 ~]# bash /work/test30.sh
mkdir: ディレクトリ `/tmp/TEST1234/TEST' を作成できません: そのようなファイルやディレクトリはありません

 

ただ、先ほども記述したように一部の処理(ループ内の処理だったり、三項演算子内だったりetc)については、正常終了でなくてもそのままスクリプトは実行されてしまうので注意が必要。

 

5.パス名の展開を無効にする

「set -f」もしくは「set -o noglob」を実行すると、シェルで「*(アスタリスク)」などでのワイルドカードでの展開を無効にする事ができる。

20151202_000001

[root@test-centos7 ~]# ls /tmp/*
/tmp/*           /tmp/date_file   /tmp/tar_test.tar      /tmp/tar_test.tar.gz
/tmp/aaaaaa.log  /tmp/dddddd.log  /tmp/tar_test.tar.bz2  /tmp/test1

/tmp/test:
test1234

/tmp/test12345678:

/tmp/test2:
[root@test-centos7 ~]#
[root@test-centos7 ~]# set -f
[root@test-centos7 ~]# ls /tmp/*
/tmp/*
[root@test-centos7 ~]# set +f
[root@test-centos7 ~]# ls /tmp/*
/tmp/*           /tmp/date_file   /tmp/tar_test.tar      /tmp/tar_test.tar.gz
/tmp/aaaaaa.log  /tmp/dddddd.log  /tmp/tar_test.tar.bz2  /tmp/test1

/tmp/test:
test1234

/tmp/test12345678:

/tmp/test2:

 

6.ブレース展開を無効にする

「set +B」もしくは「set +o braceexpand」で、シェルのブレース展開を無効にする事ができる。

20151202_000002

[root@test-centos7 ~]# echo abc{123,456,789}def
abc123def abc456def abc789def
[root@test-centos7 ~]#
[root@test-centos7 ~]# set +B
[root@test-centos7 ~]# echo abc{123,456,789}def
abc{123,456,789}def

 

7.リダイレクト時の上書きを無効にする

「set -C」および「set -o noclobber」を実行すると、リダイレクト時のファイルへの上書き(追記はできる)を無効にすることが出来る。
(ただし、「>|」を用いると上書き可能になっている)

20151202_000005

[root@test-centos7 ~]# echo 0 > /tmp/aaaaa
[root@test-centos7 ~]# cat /tmp/aaaaa
0
[root@test-centos7 ~]#
[root@test-centos7 ~]# echo 01 > /tmp/aaaaa
[root@test-centos7 ~]# cat /tmp/aaaaa
01
[root@test-centos7 ~]#
[root@test-centos7 ~]# set -C
[root@test-centos7 ~]#
[root@test-centos7 ~]# echo 0123 > /tmp/aaaaa
-bash: /tmp/aaaaa: 存在するファイルを上書きできません
[root@test-centos7 ~]# echo 0123 >> /tmp/aaaaa
[root@test-centos7 ~]# cat /tmp/aaaaa
01
0123
[root@test-centos7 ~]#
[root@test-centos7 ~]# echo 0123 >| /tmp/aaaaa
[root@test-centos7 ~]# cat /tmp/aaaaa
0123

 

8.引数を指定し直す

setコマンドにオプション無しで引数を渡すと、スクリプトの引数を設定し直す事が出来る。

20151202_000006

[root@test-centos7 ~]# set 1234 5678
[root@test-centos7 ~]# echo $2
5678
[root@test-centos7 ~]# echo $1
1234
[root@test-centos7 ~]#
[root@test-centos7 ~]# cat /work/test31.sh
#!/bin/bash
set abcdef ghijk 12345
echo $1
echo $3
echo $2
[root@test-centos7 ~]#
[root@test-centos7 ~]# bash /work/test31.sh
abcdef
12345
ghijk
[root@test-centos7 ~]# bash -x /work/test31.sh
+ set abcdef ghijk 12345
+ echo abcdef
abcdef
+ echo 12345
12345
+ echo ghijk
ghijk

 

9.現在のオプション状態を確認する

setコマンドで設定したオプション値を確認する場合、ただ「set -o」と実行することでその一覧を確認出来る。

20151202_000007

[root@test-centos7 ~]# set -o
allexport       off
braceexpand     on
emacs           on
errexit         off
errtrace        off
functrace       off
hashall         on
histexpand      on
history         on
ignoreeof       off
interactive-comments    on
keyword         off
monitor         on
noclobber       on
noexec          off
noglob          off
nolog           off
notify          off
nounset         off
onecmd          off
physical        off
pipefail        off
posix           off
privileged      off
verbose         off
vi              off
xtrace          off

 

プロフェショナル・シェルプログラミング (アスキー書籍) プロフェショナル・シェルプログラミング (アスキー書籍)

pexpectのターミナルサイズを変更する

$
0
0

pythonのpexpectを使っていて、ターミナルのサイズがおかしくなっていることに気づいたのでその備忘。
どうやらpexpcetでは、指定が無いとターミナルのサイズを「24,80」にしてしまうようだ(迷惑な…)。

スクリーンショット 2015-12-02 18.04.18.png

 

で、これだとちょっと困るので、以下の例のようにcursesで現在のターミナルサイズを取得させて、pexpectのsetwinsizeでターミナルウィンドウのサイズを修正させることにした。

#! /usr/bin/python
# -*- coding: utf-8 -*-
import pexpect
import os
import curses

# ターミナルサイズを取得
curses.setupterm()
term_lines = int(curses.tigetnum("lines"))
term_cols = int(curses.tigetnum("cols"))
print term_lines,term_cols

# pexpectを実行
foo = pexpect.spawn('bash')
foo.setwinsize(term_lines,term_cols)

# pexpectのターミナルサイズを取得
foo.expect(['$','#'])
foo.sendline('stty size')

foo.interact()

スクリーンショット 2015-12-02 18.40.24.png

n-mbp2011:~ XXXXX$ stty size
30 109
n-mbp2011:~ XXXXX$
n-mbp2011:~ XXXXX$ cat script/test.py
#! /usr/bin/python
# -*- coding: utf-8 -*-
import pexpect
import os
import curses

# ターミナルサイズを取得
curses.setupterm()
term_lines = int(curses.tigetnum("lines"))
term_cols  = int(curses.tigetnum("cols"))
print term_lines,term_cols

# pexpectを実行
foo = pexpect.spawn('bash')
foo.setwinsize(term_lines,term_cols)

# pexpectのターミナルサイズを取得
foo.expect(['$','#'])
foo.sendline('stty size')

foo.interact()
n-mbp2011:~ XXXXX$ python script/test.py
30 109
bash-3.2$ stty size
30 109
bash-3.2$

 

とりあえずこれでターミナルサイズは修正できた。

ハイパフォーマンスPython ハイパフォーマンスPython

年末に第20回シェル芸勉強会に参加してきました(復習)

$
0
0

年末の2015年12月26日、第20回シェル芸勉強会に参加してきました。
で、その際の備忘録として、どんな感じで問題を解いていったか残しておくことにする。

なお、問題・解答などなどはこちらにあるので、お題用のファイルのダウンロード(github)含めまず参照。

Q1(各ファイルごとに最大の値を抽出)

file_A-*のグループ、file_B-*のグループからそれぞれ最大の数を探して、その値をグループごとに表示させるよ、という問題。

20160103_000004

 

最初、for文使って解くんかいなと思ってたのだけどタイムオーバー。
模範解答のように、grepで空検索してファイル名を標準出力させて、それをsortさせて表示させる方が良いみたいだ。模範解答の通りにやるんじゃ進歩が無いので、最大値のみを表示させるのにteeコマンドを使ってみることにした。
…正直、あまりキレイに表示されないので、無駄な抗い感があるけど、まぁいいだろ。

grep "" file_* | sed 's/\-.//g' | sort -t: -k1,1 -k2,2nr | tee >(grep file_A -m 1) >(grep file_B -m 1) > /dev/null

20160103_000005

[root@localhost Q1]# # grepで、ファイル名:中身を標準出力で表示させる
[root@localhost Q1]# grep "" file_*
file_A-1:1
file_A-1:31351
file_A-1:3231
file_A-1:233333
file_A-1:35
file_A-1:93
file_A-2:11
file_A-2:35
file_A-2:21
file_A-2:5
file_A-2:7
file_A-2:8888
file_B-1:-32
file_B-1:12
file_B-1:46
file_B-1:7777
file_B-1:9
file_B-2:912
file_B-2:3
file_B-2:5
file_B-2:9912
file_B-2:4488
[root@localhost Q1]# # ファイル名から、余分な部分(-1とか)を置換する
[root@localhost Q1]# grep "" file_* | sed 's/\-.//g' | sort -t: -k1,1 -k2,2nr
file_A:233333
file_A:31351
file_A:8888
file_A:3231
file_A:93
file_A:35
file_A:35
file_A:21
file_A:11
file_A:7
file_A:5
file_A:1
file_B:9912
file_B:7777
file_B:4488
file_B:912
file_B:46
file_B:12
file_B:9
file_B:5
file_B:3
file_B:2
[root@localhost Q1]# # teeコマンドで、各grepのプロセスに出力を渡す。その際に出てしまう標準出力を/dev/nullで非表示にする
[root@localhost Q1]# grep "" file_* | sed 's/\-.//g' | sort -t: -k1,1 -k2,2nr | tee >(grep file_A -m 1) >(grep file_B -m 1) > /dev/null
file_B:9912
[root@localhost Q1]# file_A:233333

見てわかるように、最終的な出力がちょっと汚い・・・
別のファイルに書き出すのなら、少しはキレイになるんだけど。。。グループが増えたらコードが汚くなるので良くない解き方かも・・・

GNU Parallel使えるなら、そっちで書いた方がキレイな気がする。

grep "" file_* | sed 's/\-.//g' | sort -t: -k1,1 -k2,2nr | tee >(grep file_A -m 1 >> /tmp/aaa) >(grep file_B -m 1 >> /tmp/aaa) > /dev/null

20160103_000006

 

Q2(アンサイクロペディアのページにあるbashコードを端末上で実行させる)

アンサイクロペディアのシェル芸のページにある、カースト最上位者が日常的に書く、素数を出力するワンライナー」のコードをコマンドで取得し、それをコンソール上でそのままワンライナーで実行させるという問題。
ウェブスクレイピングの問題なんだけど、対象のページではevalという単語を持ってるのはその一行だけなので、まずはそれで取得、後はそれをbashに渡してあげるだけで実行できる。

curl -s http://ja.uncyclopedia.info/wiki/%E3%82%B7%E3%82%A7%E3%83%AB%E8%8A%B8 | grep eval | sed 's/^$.//g' | bash

20160103_000007

[root@localhost Q1]# # 対象ページのhtmlを取得して、evalでgrepする
[root@localhost Q1]# curl -s http://ja.uncyclopedia.info/wiki/%E3%82%B7%E3%82%A7%E3%83%AB%E8%8A%B8 | grep eval
$ eval eval \''n='\''{1..'$(dc -e 1000vp)'}'\'' eval eval eval echo '\'\\\\\\\\\\\\\\\'\\\\\\\'\\\'\''$(('\'\\\'\\\\\\\'\\\'\''$n'\'\\\'\\\\\\\'\\\'\''*'\'\\\'\\\\\\\'\\\\\\\\\\\\\\\'\\\'\''{2..$((1000/n))}'\'\\\'\\\\\\\\\\\\\\\'\\\\\\\'\\\'\''))'\'\\\'\\\\\\\'\\\\\\\\\\\\\\\'\'';'\' | tr ' ' \\n | sort -n | uniq -u
[root@localhost Q1]#
[root@localhost Q1]# # 余計な記述が先頭にあるので、sedで置換する
[root@localhost Q1]# curl -s http://ja.uncyclopedia.info/wiki/%E3%82%B7%E3%82%A7%E3%83%AB%E8%8A%B8 | grep eval | sed 's/^$.//g'
eval eval \''n='\''{1..'$(dc -e 1000vp)'}'\'' eval eval eval echo '\'\\\\\\\\\\\\\\\'\\\\\\\'\\\'\''$(('\'\\\'\\\\\\\'\\\'\''$n'\'\\\'\\\\\\\'\\\'\''*'\'\\\'\\\\\\\'\\\\\\\\\\\\\\\'\\\'\''{2..$((1000/n))}'\'\\\'\\\\\\\\\\\\\\\'\\\\\\\'\\\'\''))'\'\\\'\\\\\\\'\\\\\\\\\\\\\\\'\'';'\' | tr ' ' \\n | sort -n | uniq -u
[root@localhost Q1]#
[root@localhost Q1]# # 取得出来た文字列を、bashに渡して実行させる
[root@localhost Q1]# curl -s http://ja.uncyclopedia.info/wiki/%E3%82%B7%E3%82%A7%E3%83%AB%E8%8A%B8 | grep eval | sed 's/^$.//g' | bash
2
3
5
7
11
13
17
19
23
29
31
37
41
・・・

 

Q3(ファイルに記述されている奇数と偶数をそれぞれ別々にソートする)

ファイルに偶数と奇数が記述されているので、奇数を1列目で昇順、偶数を2列目で降順といった形に編集して表示させる。
本番では全然解けなかったので、模範解答を分解して記述する。

1列のものを2列にするためには、pasteコマンドを用いると良いようだ。

paste <(awk '$1%2' Q3 | sort) <(awk '$1%2==0' Q3 | sort -r) | sed 's/\t/ /g'

20160103_000008

[root@localhost vol.20]# # 1列目(奇数)
[root@localhost vol.20]# awk '$1%2' Q3 | sort
1
5
9
[root@localhost vol.20]#
[root@localhost vol.20]# # 2列目(偶数)
[root@localhost vol.20]# awk '$1%2==0' Q3 | sort -r
8
4
2
[root@localhost vol.20]#
[root@localhost vol.20]# # 1列名と2列目を合体
[root@localhost vol.20]# paste <(awk '$1%2' Q3 | sort) <(awk '$1%2==0' Q3 | sort -r)
1       8
5       4
9       2
[root@localhost vol.20]#
[root@localhost vol.20]# # タブをスペースに置換
[root@localhost vol.20]# paste <(awk '$1%2' Q3 | sort) <(awk '$1%2==0' Q3 | sort -r) | sed 's/\t/ /g'
1 8
5 4
9 2

 

Q4(sshでログインしているターミナルを自分以外強制終了させる)

ワンライナーで、sshでログインしている自分以外のターミナルを強制的に終了(kill)させる、というもの。
個人的には、今回の勉強会で一番良く解けたような気がしないでもない。

当初、ttyコマンドで以下のようにして自身のターミナルを確認しようかと思ったのだが、どうもうまく動かない。
どうやら、以下のようにコマンドを実行するとターミナルと関係の無いプロセスでttyが実行されるため、思っていたように動作しないようだ。

[root@localhost vol.20]# who
root     tty1         2016-01-03 09:04
root     pts/0        2016-01-03 09:08 (172.28.XXX.XXX)
root     pts/1        2016-01-04 01:25 (172.28.XXX.XXX)
root     pts/2        2016-01-04 01:25 (172.28.XXX.XXX)
[root@localhost vol.20]#
[root@localhost vol.20]# tty | sed 's/\/dev\///g'
pts/0
[root@localhost vol.20]#
[root@localhost vol.20]# set -vx
printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"
++ printf '\033]0;%s@%s:%s\007' root localhost /tmp/ShellGeiData/vol.20
[root@localhost vol.20]# who | grep $(tty | sed 's/\/dev\///g')
who | grep $(tty | sed 's/\/dev\///g')
+ who
++ sed 's/\/dev\///g'
++ tty
+ grep --color=auto tty $'\343\201\247\343\201\257\343\201\202\343\202\212\343\201\276\343\201\233\343\202\223'
grep: ではありません: そのようなファイルやディレクトリはありません
printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"
++ printf '\033]0;%s@%s:%s\007' root localhost /tmp/ShellGeiData/vol.20

 

このため、とりあえず以下のように最初にttyを実行することで端末情報を取得し、他の端末をkillした。

tty | sed 's/\/dev\///g' | xargs -I{} grep -v {} &lt;(ps -uh) | awk '$0=$2' | xargs kill -KILL

20160103_000009

[root@localhost vol.20]# who
root     pts/0        2016-01-03 09:08 (172.28.XXX.XXX)
root     pts/1        2016-01-04 04:16 (172.28.XXX.XXX)
root     pts/2        2016-01-04 04:16 (172.28.XXX.XXX)
root     pts/3        2016-01-04 04:16 (172.28.XXX.XXX)
[root@localhost vol.20]#
[root@localhost vol.20]# tty | sed 's/\/dev\///g' | xargs -I{} grep -v {} <(ps -uh) | awk '$0=$2' | xargs kill -KILL
[root@localhost vol.20]#
[root@localhost vol.20]# who
root     pts/0        2016-01-03 09:08 (172.28.XXX.XXX)

 

で、とりあえずこの解答で満足していたのだけど、家に帰る途中に「そもそもシェル変数使えばもっと簡単なんじゃないの?」ということに気づいたので、それで作りなおしたのが以下。
grepもawkで実施させるようにしたのだけど、こっちの方が記述もキレイだし、本来あるべき記述だと思う。

ps -uh | awk '$7!="'${SSH_TTY/\/dev\//}'" {system("sudo kill -9 "$2)}' -

20160103_000010

[root@localhost vol.20]# who
root     pts/0        2016-01-03 09:08 (172.28.XXX.XXX)
root     pts/1        2016-01-04 04:21 (172.28.XXX.XXX)
root     pts/2        2016-01-04 04:21 (172.28.XXX.XXX)
root     pts/3        2016-01-04 04:21 (172.28.XXX.XXX)
[root@localhost vol.20]#
[root@localhost vol.20]# ps -uh | awk '$7!="'${SSH_TTY/\/dev\//}'" {system("sudo kill -9 "$2)}' -
[root@localhost vol.20]#
[root@localhost vol.20]# who
root     pts/0        2016-01-03 09:08 (172.28.XXX.XXX)

 

Q5(最大公約数を求めるワンライナー)

任意の二つの自然数をechoして、最大公約数を求めるワンライナーを作るよ、という問題。
正直、全然わからんかったのだけど、ユークリッドの互除法をいい感じにコマンドに落としこむ事で解が得られるらしい。

で、模範解答ではこれをawkでやっているようだ。

echo 45 126 | awk '{while($1*$2!=0){if($1>$2){$1=$1-$2}else{$2=$2-$1}print}}' | awk 'END{print $1}'

 

Q6(対象文字列が行の何列目にあるかを出力する)

ファイルの中に記述されている人の名前が、それぞれ何列目に記述されているのかをワンライナーで出力させる、という問題。
ぶっちゃけた話、これについても、これ以降の問題についてもあまり歯が立たなかった・・・。

というわけで、以降の問題については模範解答を分解してわかった気になってみる。

sed 's/ / /g' Q6 | awk '{for(i=1;i<=NF;i++){print $i,NR,i}}' | sort -k1,2 | awk '{print $1,$3}' | xargs -n 4 | awk '{print $1,$2,$4}'

20160103_000012

[root@localhost vol.20]# # Q6ファイルの区切り文字が全角スペースなので、半角に置換する
[root@localhost vol.20]# sed 's/ / /g' Q6
山田 上田 吉田 武田
吉田 武田 上田 山田
[root@localhost vol.20]#
[root@localhost vol.20]# # 2列目に行数、3列目に何列目にその文字列が存在していたかを表示させる
[root@localhost vol.20]# sed 's/ / /g' Q6 | awk '{for(i=1;i<=NF;i++){print $i,NR,i}}'
山田 1 1
上田 1 2
吉田 1 3
武田 1 4
吉田 2 1
武田 2 2
上田 2 3
山田 2 4
[root@localhost vol.20]#
[root@localhost vol.20]# # 名前順、行順でソート
[root@localhost vol.20]# sed 's/ / /g' Q6 | awk '{for(i=1;i<=NF;i++){print $i,NR,i}}' | sort -k1,2
吉田 1 3
吉田 2 1
山田 1 1
山田 2 4
上田 1 2
上田 2 3
武田 1 4
武田 2 2
[root@localhost vol.20]#
[root@localhost vol.20]# # 2列目(何行目か)の表示を除外する
[root@localhost vol.20]# sed 's/ / /g' Q6 | awk '{for(i=1;i<=NF;i++){print $i,NR,i}}' | sort -k1,2 | awk '{print $1,$3}'
吉田 3
吉田 1
山田 1
山田 4
上田 2
上田 3
武田 4
武田 2
[root@localhost vol.20]#
[root@localhost vol.20]# # xargsへ渡す引数を4(名前、列数、名前、列数)として次のコマンドに引き渡す
[root@localhost vol.20]# sed 's/ / /g' Q6 | awk '{for(i=1;i<=NF;i++){print $i,NR,i}}' | sort -k1,2 | awk '{print $1,$3}' | xargs -n 4
吉田 3 吉田 1
山田 1 山田 4
上田 2 上田 3
武田 4 武田 2
[root@localhost vol.20]#
[root@localhost vol.20]# # 3列目の表示を除外する
[root@localhost vol.20]# sed 's/ / /g' Q6 | awk '{for(i=1;i<=NF;i++){print $i,NR,i}}' | sort -k1,2 | awk '{print $1,$3}' | xargs -n 4 | awk '{print $1,$2,$4}'
吉田 3 1
山田 1 4
上田 2 3
武田 4 2

 

Q7(「魚」という部分を持つ漢字をなるべく多く列挙する)

「魚」という字を含んでいる漢字を、一つでも多く出力させるという問題。
手法は問わないとなっているが、基本的にはWEBスクレイピングか日本語コードで該当する範囲の数字を文字列として出力させるというもの。

模範解答では後者の手法が取られている。

seq 39770 40058 | xargs printf "&#x%x;" | nkf --numchar-input

20160103_000013

 

・・・まぁ、なんといいますか。
手元の環境だと全部の文字をちゃんと表示出来なかったので分かりにくいと思うのだけど、ちゃんと表示がされるのでご安心ください。

 

Q8(漢数字→アラビア数字の変換)

漢数字で書かれた内容をアラビア数字に変換する、というもの。
残念ながら、単体のコマンドを探して見たのだけど見つけられ無かった・・・

模範解答では一度sedで漢数字をアラビア数字に何も考えずに置換して、その後「十」とか「百」と言った漢字表記を別途計算する対応を行っている。

sed 'y/一二三四五六七八九/123456789/' Q8 | sed -e 's/十/1*10+/' -e 's/百/1*100+/' -e 's/千/1*1000+/' -e 's/万/1*10000+/' -e 's/\([0-9]\)1/\1/g' | bc

20160103_000014

blacknon@X201:~/20151226_shellgei/ShellGeiData/vol.20$ cat Q8
五千七百三十五
四千三
四十五
九万六千二百三十三
十一
百十二
blacknon@X201:~/20151226_shellgei/ShellGeiData/vol.20$ # 漢字数字を単純にアラビア数字に置換する
blacknon@X201:~/20151226_shellgei/ShellGeiData/vol.20$ sed 'y/一二三四五六七八九/123456789/' Q8
5千7百3十5
4千3
4十5
9万6千2百3十3
十1
百十2
blacknon@X201:~/20151226_shellgei/ShellGeiData/vol.20$
blacknon@X201:~/20151226_shellgei/ShellGeiData/vol.20$ # 「十」「百」といった数字について、掛け算表記に変換する
blacknon@X201:~/20151226_shellgei/ShellGeiData/vol.20$ sed 'y/一二三四五六七八九/123456789/' Q8 | sed -e 's/十/1*10+/' -e 's/百/1*100+/' -e 's/千/1*1000+/' -e 's/万/1*10000+/' -e 's/\([0-9]\)1/\1/g'

5*1000+7*100+3*10+5
4*1000+3
4*10+5
9*10000+6*1000+2*100+3*10+3
1*10+1
1*100+1*10+2
blacknon@X201:~/20151226_shellgei/ShellGeiData/vol.20$
blacknon@X201:~/20151226_shellgei/ShellGeiData/vol.20$ # 掛け算表記の内容を計算させる
blacknon@X201:~/20151226_shellgei/ShellGeiData/vol.20$ sed 'y/一二三四五六七八九/123456789/' Q8 | sed -e 's/十/1*10+/' -e 's/百/1*100+/' -e 's/千/1*1000+/' -e 's/万/1*10000+/' -e 's/\([0-9]\)1/\1/g' | bc
5735
4003
45
96233
11
112

 

 

とりあえず、復習としては以上だろうか。
う~ん…あんまり歯が立たなかったなぁ…

次回は、もう少し健闘したいと思う。

 

シェルプログラミング実用テクニック シェルプログラミング実用テクニック

Linuxで複数ファイルをリネームして一括コピーする

$
0
0

仕事で、大量にあるファイルの一部分のみをリネームしてコピーを行いたい事があったので、その備忘。
イメージとしては、以下のようなファイルがあって、それの一部、例えば以下の例だとhostname_aaa_*をhostname_bbb_*へリネームコピーしたい、といった具合。

20160103_000000

[root@localhost work]# ls -la /work
合計 32
drwxr-xr-x.  2 root root 4096  1月  3 09:20 .
dr-xr-xr-x. 18 root root 4096  1月  3 09:08 ..
-rw-r--r--.  1 root root    8  1月  3 09:20 hostname_aaa_000.txt
-rw-r--r--.  1 root root    8  1月  3 09:20 hostname_aaa_001.txt
-rw-r--r--.  1 root root    8  1月  3 09:20 hostname_aaa_002.txt
-rw-r--r--.  1 root root    8  1月  3 09:20 hostname_aaa_003.txt
-rw-r--r--.  1 root root    8  1月  3 09:20 hostname_aaa_004.txt
-rw-r--r--.  1 root root    8  1月  3 09:20 hostname_aaa_005.txt
[root@localhost work]# grep "" /work/*
/work/hostname_aaa_000.txt:aaa_000
/work/hostname_aaa_001.txt:aaa_001
/work/hostname_aaa_002.txt:aaa_002
/work/hostname_aaa_003.txt:aaa_003
/work/hostname_aaa_004.txt:aaa_004
/work/hostname_aaa_005.txt:aaa_005

 

こういった場合に、いちいちファイルを一個づつコピーするなんて面倒な事はしたくない。
という訳で、以下のコマンドで一括コピーを行う事にした。

for i in `ls *コピー元*`; do cp $i `echo $i | sed "s/置換前文字列/置換後文字列/g"`; done

20160103_000002

[root@localhost work]# ls -la /work
合計 32
drwxr-xr-x.  2 root root 4096  1月  3 09:25 .
dr-xr-xr-x. 18 root root 4096  1月  3 09:08 ..
-rw-r--r--.  1 root root    8  1月  3 09:20 hostname_aaa_000.txt
-rw-r--r--.  1 root root    8  1月  3 09:20 hostname_aaa_001.txt
-rw-r--r--.  1 root root    8  1月  3 09:20 hostname_aaa_002.txt
-rw-r--r--.  1 root root    8  1月  3 09:20 hostname_aaa_003.txt
-rw-r--r--.  1 root root    8  1月  3 09:20 hostname_aaa_004.txt
-rw-r--r--.  1 root root    8  1月  3 09:20 hostname_aaa_005.txt
[root@localhost work]#
[root@localhost work]# grep "" /work/*
/work/hostname_aaa_000.txt:aaa_000
/work/hostname_aaa_001.txt:aaa_001
/work/hostname_aaa_002.txt:aaa_002
/work/hostname_aaa_003.txt:aaa_003
/work/hostname_aaa_004.txt:aaa_004
/work/hostname_aaa_005.txt:aaa_005
[root@localhost work]# for i in `ls /work/hostname_aaa_*.txt`; do cp $i `echo $i | sed "s/aaa/bbb/g"`; done
[root@localhost work]#
[root@localhost work]# ls -la /work
合計 56
drwxr-xr-x.  2 root root 4096  1月  3 09:26 .
dr-xr-xr-x. 18 root root 4096  1月  3 09:08 ..
-rw-r--r--.  1 root root    8  1月  3 09:20 hostname_aaa_000.txt
-rw-r--r--.  1 root root    8  1月  3 09:20 hostname_aaa_001.txt
-rw-r--r--.  1 root root    8  1月  3 09:20 hostname_aaa_002.txt
-rw-r--r--.  1 root root    8  1月  3 09:20 hostname_aaa_003.txt
-rw-r--r--.  1 root root    8  1月  3 09:20 hostname_aaa_004.txt
-rw-r--r--.  1 root root    8  1月  3 09:20 hostname_aaa_005.txt
-rw-r--r--.  1 root root    8  1月  3 09:26 hostname_bbb_000.txt
-rw-r--r--.  1 root root    8  1月  3 09:26 hostname_bbb_001.txt
-rw-r--r--.  1 root root    8  1月  3 09:26 hostname_bbb_002.txt
-rw-r--r--.  1 root root    8  1月  3 09:26 hostname_bbb_003.txt
-rw-r--r--.  1 root root    8  1月  3 09:26 hostname_bbb_004.txt
-rw-r--r--.  1 root root    8  1月  3 09:26 hostname_bbb_005.txt
[root@localhost work]#
[root@localhost work]# grep "" /work/hostname_bbb_00*
/work/hostname_bbb_000.txt:aaa_000
/work/hostname_bbb_001.txt:aaa_001
/work/hostname_bbb_002.txt:aaa_002
/work/hostname_bbb_003.txt:aaa_003
/work/hostname_bbb_004.txt:aaa_004
/work/hostname_bbb_005.txt:aaa_005

 

Ansibleのyamlファイルとかでホスト名ごとに作成されている場合とか(今回の場合それ)に使えるだろう。

まんがでわかるLinux シス管系女子 2(日経BP Next ICT選書) まんがでわかるLinux シス管系女子 2(日経BP Next ICT選書)

Linuxの標準出力の内容を複数のプロセスに渡す

$
0
0

Linuxで、標準出力の内容をそのまま複数のプロセスに渡したい時がある。
そんなときは、teeコマンドを用いると良いだろう。

コマンド | tee &gt;(コマンド1) &gt;(コマンド2) .... | コマンドN

もしくは

コマンド | tee &gt;(コマンド1) &gt;(コマンド2) ... 1 > /dev/null

これを用いる事で、以下のようにechoで出力した値に対し、複数の処理を行うことができる。
…まぁ、処理される順番は順不同なので、そこはご愛嬌ということで。

echo 1234 | tee &gt;(sed 's/34/56/g') &gt;(sed 's/34/78/g') | sed 's/34/90/g'

20160103_000015

[root@localhost ~]# echo 1234 | tee >(sed 's/34/56/g') >(sed 's/34/78/g') | sed 's/34/90/g'
1290
1278
1256

 

色々と使いドコロが難しい気もするけど、ファイルに書き出すのであれば(順不同だけど)うまく動作するだろう。
もしGNU parallelが使える環境であれば、そちらのほうがいいかも知れない。GNU Parallel使ったことないけど。

まんがでわかるLinux シス管系女子2(日経BPパソコンベストムック) まんがでわかるLinux シス管系女子2(日経BPパソコンベストムック)

Linuxのpingコマンドの出力結果にタイムスタンプを付与する

$
0
0

Linuxでpingコマンドを打ち続けていると、どの時間帯では疎通が取れていたのに、この時間帯からは疎通が取れなくなった、というような情報が欲しい事がある。
だが、残念ながら現時点ではpingのオプションにタイムスタンプを追記するような機能は無い。。。というと嘘になって、「-D」というオプションがあるにはあるんだけど。。。UNIX時刻で表示するようなのだ。

[root@localhost ~]# ping -D 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
[1451860419.746687] 64 bytes from 8.8.8.8: icmp_seq=1 ttl=54 time=5.20 ms
[1451860420.748230] 64 bytes from 8.8.8.8: icmp_seq=2 ttl=54 time=5.36 ms
[1451860421.761398] 64 bytes from 8.8.8.8: icmp_seq=3 ttl=54 time=16.9 ms
[1451860422.751211] 64 bytes from 8.8.8.8: icmp_seq=4 ttl=54 time=5.67 ms
[1451860423.755277] 64 bytes from 8.8.8.8: icmp_seq=5 ttl=54 time=7.93 ms
[1451860424.757697] 64 bytes from 8.8.8.8: icmp_seq=6 ttl=54 time=9.29 ms
[1451860425.755846] 64 bytes from 8.8.8.8: icmp_seq=7 ttl=54 time=6.05 ms
[1451860426.758742] 64 bytes from 8.8.8.8: icmp_seq=8 ttl=54 time=7.70 ms
[1451860427.763093] 64 bytes from 8.8.8.8: icmp_seq=9 ttl=54 time=10.2 ms
[1451860428.760407] 64 bytes from 8.8.8.8: icmp_seq=10 ttl=54 time=6.18 ms
[1451860429.761970] 64 bytes from 8.8.8.8: icmp_seq=11 ttl=54 time=6.42 ms
[1451860430.763397] 64 bytes from 8.8.8.8: icmp_seq=12 ttl=54 time=6.29 ms

 

では、どうやってタイムスタンプを付与するのかというと、もうこのオプションには頼らず、dateコマンドと組み合わせてwhileで実行させる。

ping 対象ホスト | while read pi; do echo "$(date '+[%Y/%m/%d %H:%M:%S]') $pi"; done

20160103_000017

[root@localhost ~]# ping 8.8.8.8 | while read pi; do echo "$(date '+[%Y/%m/%d %H:%M:%S]') $pi"; done
[2016/01/04 07:37:33] PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
[2016/01/04 07:37:33] 64 bytes from 8.8.8.8: icmp_seq=1 ttl=54 time=6.44 ms
[2016/01/04 07:37:34] 64 bytes from 8.8.8.8: icmp_seq=2 ttl=54 time=6.06 ms
[2016/01/04 07:37:35] 64 bytes from 8.8.8.8: icmp_seq=3 ttl=54 time=7.00 ms
[2016/01/04 07:37:36] 64 bytes from 8.8.8.8: icmp_seq=4 ttl=54 time=7.75 ms
[2016/01/04 07:37:37] 64 bytes from 8.8.8.8: icmp_seq=5 ttl=54 time=13.0 ms
[2016/01/04 07:37:38] 64 bytes from 8.8.8.8: icmp_seq=6 ttl=54 time=4.65 ms
[2016/01/04 07:37:39] 64 bytes from 8.8.8.8: icmp_seq=7 ttl=54 time=5.12 ms

xargsを用いる方法もある。

ping 8.8.8.8 | xargs -L 1 -I '{}' date '+[%Y/%m/%d %H:%M:%S] {}'

 

perlを用いる手法もあるようだ。

ping 8.8.8.8 | perl -MPOSIX -ne 'print strftime("%c ", localtime), $_'

 

とりあえず、いくつか方法はあるようなので、好きなので対応すると良いだろう。
そもそも、こんなことしなくても「-D」以外のオプションで人間の読める時間を出すようにしてもらえれば話は解決する気がするけど、まぁそのうち実装されるのだろう。

シェルプログラミング実用テクニック シェルプログラミング実用テクニック シェルプログラミング実用テクニック シェルプログラミング実用テクニック

Proxmox VE 4.0でUSBパススルーを実施する

$
0
0

この度、ラックを買ったので自宅環境を一新するにあたり、仮想基盤を全てProxmoxで統一(一部テスト用にESXi)したのだけど、その際に仮想マシンにUSBパススルー設定をする必要があったのでその備忘。
WebUIから設定が行えないので、基本的にCUIで設定を行う必要がある。

まず、ProxmoxVEホストにssh接続し、lsusbでパススルーしたいUSBのBUSを確認する。

lsusb
root@BS-PHY-PROX-01:~# lsusb
Bus 002 Device 002: ID 0bda:817f Realtek Semiconductor Corp. RTL8188RU 802.11n WLAN Adapter
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 008 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 007 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 006 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 005 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 004 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 003 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub

今回の場合、一行目のデバイスをパススルーするのだが、その際に重要なのが赤字で記載している値。
この値を仮想マシンファイルに記述する必要がある。

仮想マシンファイルは、基本的には「/etc/pve/nodes/ホスト名/qemu-server/仮想マシンID.conf」として設置されている(別にディレクトリをマウントしてそこに仮想マシンを作成している場合はこの限りではない)ので、このファイルに以下の内容を追記する。

usb0: host=0bda:817f

 

これで仮想マシンへのUSBパススルーは完了。
簡単な設定ではあるけど、できればWebUIから実施できるようになってほしいところではある。

 

改訂新版VMwareの基本~仮想化/クラウドのための設計・構築・運用のポイントがわかる 改訂新版VMwareの基本~仮想化/クラウドのための設計・構築・運用のポイントがわかる

timeoutコマンドによる指定時間経過時の処理切り替え

$
0
0

仕事で、わざわざその為にスクリプトを組むのも面倒な、プロセス停止に時間がかかるようであればプロセスをkillしてしまうという対応があった。
面倒なのでワンライナーで対処できないかなぁ。。。と思い調べたところ、Linuxのディストリではtimeoutコマンドというものが用意されているようだ。

使い方は簡単で、以下のようにtimeoutコマンドを実行するだけだ。

timeout 待機時間(秒) 実行コマンド

 

で、実行コマンドが待機秒内で終了しない場合、exitコード124で異常終了する。

20160108_000000

[root@BS-PUB-CENT7-01 ~]# # 5秒でタイムアウト(2秒sleep)
[root@BS-PUB-CENT7-01 ~]# time timeout 5 sleep 2;echo $?

real    0m2.005s
user    0m0.001s
sys     0m0.003s
0
[root@BS-PUB-CENT7-01 ~]#
[root@BS-PUB-CENT7-01 ~]#
[root@BS-PUB-CENT7-01 ~]# # 5秒でタイムアウト(10秒sleep)
[root@BS-PUB-CENT7-01 ~]# time timeout 5 sleep 10;echo $?

real    0m5.004s
user    0m0.001s
sys     0m0.003s
124

ということは、以下のように記述することでタイムアウト時の分岐処理を一行で記述できる。

timeout 待機時間(秒) 実行コマンド || timeout時の実行コマンド

20160108_000001

[root@BS-PUB-CENT7-01 ~]# # 5秒でタイムアウト(2秒sleep)
[root@BS-PUB-CENT7-01 ~]# time timeout 5 sleep 2 || echo "Timeout Error"

real    0m2.005s
user    0m0.002s
sys     0m0.003s
[root@BS-PUB-CENT7-01 ~]#
[root@BS-PUB-CENT7-01 ~]# # 5秒でタイムアウト(10秒sleep)
[root@BS-PUB-CENT7-01 ~]# time timeout 5 sleep 10 || echo "Timeout Error"

real    0m5.003s
user    0m0.000s
sys     0m0.004s
Timeout Error

 

これで、ひとまずは対処出来たかな。

Linuxシステム[実践]入門 (Software Design plus) Linuxシステム[実践]入門 (Software Design plus)

jqコマンドで値の有無(null)を判別させる

$
0
0

最近、仕事でAWSやAzureを利用するようになってから、JSON形式のファイルに触れる事が多くなってきた。
JSON形式のファイルをイジる場合、MacやLinux環境だとjqコマンドというものを用いると楽に整形出来るので良く利用しているのだけど、これで特定の項目がnullの場合(nullじゃない場合)に対象のデータを表示させるような使い方(具体的には、AzureのパブリックIPに対してhostsの自動生成をする際、払いだされてない仮想マシンを除外するため)が必要になったので、その備忘。

jqコマンドで、項目の値に応じて表示/非表示を切り替える場合には、「select」を用いる。
なので、その項目がnullの場合だと、以下のようにコマンドを実行する。

jq 'select(.ipAddress ==null)' #nullの時
jq 'select(.ipAddress !=null)' #nullじゃない時

20160111_000000

[root@localhost ~]# cat /tmp/test.json | jq 'select(.ipAddress ==null)'
{
  "name": "A3",
  "ipAddress": null
}
[root@localhost ~]#
[root@localhost ~]# # NULLの時
[root@localhost ~]# cat /tmp/test.json | jq 'select(.ipAddress ==null)'
{
  "name": "A3",
  "ipAddress": null
}
[root@localhost ~]#
[root@localhost ~]# # NULLじゃない時
[root@localhost ~]# cat /tmp/test.json | jq 'select(.ipAddress !=null)'
{
  "name": "A1",
  "ipAddress": "192.168.0.100"
}
{
  "name": "A2",
  "ipAddress": "192.168.0.101"
}
JS+Node.jsによるWebクローラー/ネットエージェント開発テクニック JS+Node.jsによるWebクローラー/ネットエージェント開発テクニック

ProxmoxVE4でPCIパススルーを行ってみた

$
0
0

以前、Proxmox VE 3.1でPCIパススルーを行っているが、それと同様の処理をProxmox VE 4でも行ってみる。
前回と同じく、まずは以下のコマンドでgrubを編集し、Intel VT-dを有効にする。

sed -i '/GRUB_CMDLINE_LINUX_DEFAULT/cGRUB_CMDLINE_LINUX_DEFAULT="quiet iommu=pt intel_iommu=on vfio_iommu_type1.allow_unsafe_interrupts=1"' /etc/default/grub
update-grub

 

再起動後、以下のコマンドでInter VT-dが有効になっている事(「IOMMU enabled」という記述があること)を確認する。

dmesg | grep -e DMAR -e IOMMU

20160111_000001

 

上記が確認出来たら、仮想マシンの設定ファイルを編集しパススルー設定を行う。
まず、lspciコマンドで対象のPCIバスを確認する。出力の一番左にある「03:00.0」が指定するBUSにあたる。

lspci | grep Multimedia
root@BS-PHY-PROX-01:~# lspci | grep Multimedia
03:00.0 Multimedia controller: Altera Corporation Device 4c15 (rev 01)

次に、この値をパススルーする仮想マシンの設定ファイル(基本的には「/etc/pve/nodes/PROXMOXホスト名/qemu-server/仮想マシンID.conf」)に、以下の内容を追記する。

hostpci0: PCIのBUS(今回の場合「03:00.0」)

 

これで、後は対象の仮想マシンを起動するだけだ。
起動後、仮想マシン上でlspciを実行した結果がこちら。

20160112_000000

 

基本的には、ProxmoxVE3.1と変わりないようだ。

すべてわかる仮想化大全2016(日経BPムック) すべてわかる仮想化大全2016(日経BPムック)

Linux/UNIXでsed or awkを使ってファイルの特定列だけ置き換える

$
0
0

LinuxやUNIXで、区切り文字で句切られているファイルの、特定の列だけ値を置き換える場合は、sedかawkを用いる事で楽に行う事ができる。

sedで行う場合

sedで特定列のみ置き換える場合は、以下のようにコマンドを実行する。

sed '{s/"区切り文字"[^"区切り文字"]*}/"区切り文字"置換後の文字/置き換える列-1} 対象ファイル

 

例えば、「,(カンマ)」で句切られたファイルの3列目を「hige」に置き換える場合だと、以下のように記述する。

sed '{s/,[^,]*/,hige/2}' 対象ファイル

20160114_000000

[root@localhost ~]# cat /tmp/test.file
aaaaa,11111,super,66666661
bbbbb,22222,wonder,66666662
ccccc,33333,dorderar,66666663
ddddd,44444,atacker,66666664
eeeee,55555,pepsi,66666665
fffff,66666,papet,66666666
ggggg,77777,dagashikasi,66666667
hhhhh,88888,goemon,66666668

[root@localhost ~]# sed '{s/,[^,]*/,hige/2}' /tmp/test.file
aaaaa,11111,hige,66666661
bbbbb,22222,hige,66666662
ccccc,33333,hige,66666663
ddddd,44444,hige,66666664
eeeee,55555,hige,66666665
fffff,66666,hige,66666666
ggggg,77777,hige,66666667
hhhhh,88888,hige,66666668

 

特定の行のみを置き換える場合は、以下のように行の条件を指定する。
例えば、「bbbbb」で始まる列を置き換える場合は以下のようにする。

sed '/^bbbbb/{s/,[^,]*/,hige/2}' 対象ファイル

20160114_000001

[root@localhost ~]# sed '/^bbbbb/{s/,[^,]*/,hige/2}' /tmp/test.file
aaaaa,11111,super,66666661
bbbbb,22222,hige,66666662
ccccc,33333,dorderar,66666663
ddddd,44444,atacker,66666664
eeeee,55555,pepsi,66666665
fffff,66666,papet,66666666
ggggg,77777,dagashikasi,66666667
hhhhh,88888,goemon,66666668

awkで行う場合

awkで行う場合は、もっと簡単に行える。

awk '{FS="区切り文字";OFS="区切り文字"}{$置き換える列番号="置換後の文字列"}1' 対象ファイル

 

例えば、2列目を「999000」に置換する場合、以下のようにコマンドを実行する。

awk '{FS=",";OFS=","}{$2="999000"}1' 対象ファイル

20160114_000002

[root@localhost ~]# cat /tmp/test.file
aaaaa,11111,super,66666661
bbbbb,22222,wonder,66666662
ccccc,33333,dorderar,66666663
ddddd,44444,atacker,66666664
eeeee,55555,pepsi,66666665
fffff,66666,papet,66666666
ggggg,77777,dagashikasi,66666667
hhhhh,88888,goemon,66666668

[root@localhost ~]# awk 'BEGIN {FS=",";OFS=","}{$2="999000"}1' /tmp/test.file
aaaaa,999000,super,66666661
bbbbb,999000,wonder,66666662
ccccc,999000,dorderar,66666663
ddddd,999000,atacker,66666664
eeeee,999000,pepsi,66666665
fffff,999000,papet,66666666
ggggg,999000,dagashikasi,66666667
hhhhh,999000,goemon,66666668
,999000

 

特定の行にしぼって更新する場合は、以下のように条件をつけると良いだろう。
以下の例では、3列目が「pepsi」の行のみ、2列目を置換するように指定している。

20160114_000003

[root@localhost ~]# awk 'BEGIN {FS=",";OFS=","}$3=="pepsi"{$2="999000"}1' /tmp/test.file
aaaaa,11111,super,66666661
bbbbb,22222,wonder,66666662
ccccc,33333,dorderar,66666663
ddddd,44444,atacker,66666664
eeeee,999000,pepsi,66666665
fffff,66666,papet,66666666
ggggg,77777,dagashikasi,66666667
hhhhh,88888,goemon,66666668

 

 

AWK実践入門 (Software Design plus) AWK実践入門 (Software Design plus)

UNIX/Linuxでコマンドのexitコードを反転させる

$
0
0

仕事で、正常終了時にコマンドのexitコードを0に、異常終了時には1にしたいとの話があり、やり方ってなんか無いのかな?と調べたので、その備忘。
やり方は簡単で、単に対象のコマンド実行時に頭に「!」をつけるだけだ。

! exitコードを反転させたいコマンド

実際に、lsコマンドで試してみよう。

20160116_000000

[root@localhost ~]# # 存在するファイルをlsで指定(exitコードは0)
[root@localhost ~]# ls -la /work/hostname_aaa_001.txt
-rw-r--r--. 1 root root 8  1月  3 09:20 /work/hostname_aaa_001.txt
[root@localhost ~]# echo $?
0
[root@localhost ~]#
[root@localhost ~]# # 存在しないファイルをlsで指定(exitコードは1)
[root@localhost ~]# ls -la /work/hostname_aaa_100.txt
ls: /work/hostname_aaa_100.txt にアクセスできません: そのようなファイルやディレクトリはありません
[root@localhost ~]# echo $?
2
[root@localhost ~]#
[root@localhost ~]#
[root@localhost ~]# # 存在するファイルをlsで指定(exitコードは反転されて1)
[root@localhost ~]# ! ls -la /work/hostname_aaa_001.txt
-rw-r--r--. 1 root root 8  1月  3 09:20 /work/hostname_aaa_001.txt
[root@localhost ~]# echo $?
1
[root@localhost ~]#
[root@localhost ~]# # 存在しないファイルをlsで指定(exitコードは反転されて0)
[root@localhost ~]# ! ls -la /work/hostname_aaa_100.txt
ls: /work/hostname_aaa_100.txt にアクセスできません: そのようなファイルやディレクトリはありません
[root@localhost ~]# echo $?
0

0以外だったら0、0だったら1に変換している事がわかる。
何かしらの判定でexitコードの意味を反転させたいなら、これで対応できるのでは無いだろうか?

AWK実践入門 (Software Design plus) AWK実践入門 (Software Design plus)

CentOS 7をActive Directoryのドメインに参加させる

$
0
0

自宅にSamba4を用いたDomain Controllerを構築したので、それにCentOS 7を参加させてみる事にする。
まずは参加させるCentOS 7側で、以下のコマンドを実行し必要になるパッケージをインストールする。

1.必要パッケージの導入

yum -y install realmd sssd oddjob oddjob-mkhomedir adcli samba-common

 

2.AD参加設定

次に、参照するDNSサーバをDCのアドレスに変更する。

nmcli c modify インターフェイス名 ipv4.dns DCのアドレス
nmcli c down インターフェイス名; nmcli c up インターフェイス名

 

以下のコマンドを実行しActive Directoryに関する情報をDCから取得出来る事を確認する。

realm discover レルム名
[root@BS-PUB-PRODUCT ~]# realm discover BLACKNON.LOCAL
blacknon.local
  type: kerberos
  realm-name: BLACKNON.LOCAL
  domain-name: blacknon.local
  configured: kerberos-member
  server-software: active-directory
  client-software: winbind
  required-package: oddjob-mkhomedir
  required-package: oddjob
  required-package: samba-winbind-clients
  required-package: samba-winbind
  required-package: samba-common
  login-formats: %U
  login-policy: allow-any-login

 

無事、Active Directoryの情報が取得出来ることを確認したら、以下のコマンドでActive Directoryへのログイン設定を行う。

authconfig-tui

20160117_000003

ユーザー情報:
[*] Winbindを使用
認証:
[*] Winbind認証を使用

 

20160117_000004

セキュリティモデル: ads
ドメイン: ドメイン名
ドメインコントローラー: DCサーバ名
ADSレルム(Realm): レルム名
テンプレートシェル: /bin/bash

設定後、「OK」を選択する。
この時点では、まだドメイン参加は行わない。以下のコマンドを実行し、一部設定を変更する。

authconfig --enablemkhomedir --update
sed -i '/winbind use default domain/s/false/true/g' /etc/samba/smb.conf
systemctl restart winbind

 

後は、以下のコマンドでドメインへの参加を行う。

net ads join -U Administrator
[root@BS-PUB-PRODUCT ~]# net ads join -U Administrator
Enter Administrator's password:
Using short domain name -- BLACKNON
Joined 'BS-PUB-PRODUCT' to dns domain 'blacknon.local'
No DNS domain configured for bs-pub-product. Unable to perform DNS Update.
DNS update failed: NT_STATUS_INVALID_PARAMETER

 

これで、無事ドメイン参加することができた。
ログイン情報は、以下のコマンドで確認できる。

net ads info
LDAP server: XXX.XXX.XXX.XXX
LDAP server name: bs-pub-domainc.blacknon.local
Realm: BLACKNON.LOCAL
Bind Path: dc=BLACKNON,dc=LOCAL
LDAP port: 389
Server time: 日, 17  1月 2016 21:16:04 JST
KDC server: XXX.XXX.XXX.XXX
Server time offset: 0

 

3.ADユーザへの切り替え

さて、それではADユーザに切り替えてみよう。
ADユーザへの切り替えは、以下のコマンドで行える。

su - レルム名\\ユーザ名

20160117_000005

 

これで無事、CentOS 7でドメイン連携が出来るようになった。

 

絵で見てわかるWindowsインフラの仕組み 絵で見てわかるWindowsインフラの仕組み

Linux/UNIXでプロセスごとのリソース消費量を確認する

$
0
0

Linux/UNIXで、OS全体ではなく特定のプロセスで使用しているリソースのみを取得したい場合は、主に以下の2通りになるだろう。

1.psコマンドで取得する

psコマンドでは、「u」を付与することでCPUやメモリ使用率について取得することも出来る。
例えば、以下の例では全ユーザで実行している、topコマンドについてCPU・メモリ使用率を出力させている(中身はgrepっぽいので、そのものずばりだけ抽出出来ないけど)。

ps au -C top

20160120_000000

[root@localhost ~]# ps au -C top
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root     15680  0.0  0.0 115380  2040 pts/0    Ss   16:42   0:00 -bash
root     15759  0.0  0.0 115380  2020 pts/1    Ss   17:27   0:00 -bash
root     15776  0.1  0.0 146136  1928 pts/1    S+   17:27   0:00 top
root     15787  0.0  0.0 139496  1572 pts/0    R+   17:27   0:00 ps au -C top
root     23173  0.0  0.0 110028   816 tty1     Ss+   1月04   0:00 /sbin/agetty --noclear tty1 linux

 

2.pidstatを用いる

sysstatをインストールしている環境であれば、pidstatを使ってプロセスごとのリソース消費量を調査することも出来る。
もしsysstatが無いようであれば、RHEL系・Debian系であれば以下のようにyum・aptでインストールすることができる。

●RHEL系

yum install sysstat

 

●Debian系

apt-get install sysstat

 

後は、以下のように指定することでvmstatと同じように使うことが出来る。

pidstat -p プロセスID 間隔 カウント数

20160120_000001

[root@localhost ~]# ps -ef | grep top
root     15776 15759  0 17:27 pts/1    00:00:00 top
root     15848 15831  0 17:35 pts/2    00:00:00 top
root     15874 15680  0 17:38 pts/0    00:00:00 grep --color=auto top
[root@localhost ~]# pidstat -p 15776 1 10
Linux 3.10.0-327.el7.x86_64 (localhost.localdomain)     2016年01月20日  _x86_64_        (2 CPU)

17時38分40秒   UID       PID    %usr %system  %guest    %CPU   CPU  Command
17時38分41秒     0     15776    0.00    0.00    0.00    0.00     1  top
17時38分42秒     0     15776    0.00    0.00    0.00    0.00     1  top
17時38分43秒     0     15776    0.00    0.00    0.00    0.00     1  top
17時38分44秒     0     15776    0.00    0.00    0.00    0.00     1  top
17時38分45秒     0     15776    0.00    0.00    0.00    0.00     1  top
17時38分46秒     0     15776    0.00    0.00    0.00    0.00     1  top
17時38分47秒     0     15776    0.00    0.00    0.00    0.00     1  top
17時38分48秒     0     15776    0.00    0.00    0.00    0.00     1  top
17時38分49秒     0     15776    0.00    0.00    0.00    0.00     1  top
17時38分50秒     0     15776    0.00    0.00    0.00    0.00     1  top
平均値:      0     15776    0.00    0.00    0.00    0.00     -  top

複数のプロセス番号を指定する場合は、「-p」で再度プロセス番号を指定してあげる事が出来る。
また、「-C」で実行されているコマンド名を指定することもできる。

20160120_000003

[root@localhost ~]# ps -ef | grep top
root     15776 15759  0 17:27 pts/1    00:00:00 top
root     15848 15831  0 17:35 pts/2    00:00:00 top
root     15884 15680  0 17:40 pts/0    00:00:00 grep --color=auto top
[root@localhost ~]# pidstat -p 15776 -p 15848 1 3
Linux 3.10.0-327.el7.x86_64 (localhost.localdomain)     2016年01月20日  _x86_64_        (2 CPU)

17時40分58秒   UID       PID    %usr %system  %guest    %CPU   CPU  Command
17時40分59秒     0     15776    0.00    0.00    0.00    0.00     1  top
17時40分59秒     0     15848    0.00    0.00    0.00    0.00     1  top

17時40分59秒   UID       PID    %usr %system  %guest    %CPU   CPU  Command
17時41分00秒     0     15776    0.00    0.00    0.00    0.00     1  top
17時41分00秒     0     15848    0.00    0.00    0.00    0.00     1  top

17時41分00秒   UID       PID    %usr %system  %guest    %CPU   CPU  Command
17時41分01秒     0     15776    0.00    0.00    0.00    0.00     1  top
17時41分01秒     0     15848    0.00    0.00    0.00    0.00     1  top

平均値:    UID       PID    %usr %system  %guest    %CPU   CPU  Command
平均値:      0     15776    0.00    0.00    0.00    0.00     -  top
平均値:      0     15848    0.00    0.00    0.00    0.00     -  top
[root@localhost ~]#
[root@localhost ~]# pidstat -C top 5 2
Linux 3.10.0-327.el7.x86_64 (localhost.localdomain)     2016年01月20日  _x86_64_        (2 CPU)

17時41分13秒   UID       PID    %usr %system  %guest    %CPU   CPU  Command
17時41分18秒     0     15776    0.20    0.00    0.00    0.20     1  top

17時41分18秒   UID       PID    %usr %system  %guest    %CPU   CPU  Command
17時41分23秒     0     15848    0.00    0.20    0.00    0.20     1  top

平均値:    UID       PID    %usr %system  %guest    %CPU   CPU  Command
平均値:      0     15776    0.10    0.00    0.00    0.10     -  top
平均値:      0     15848    0.00    0.10    0.00    0.10     -  top

 

イラストでそこそこわかる LPIC 1年生 (Linux教科書) イラストでそこそこわかる LPIC 1年生 (Linux教科書)

Linux/UNIXのコンソール上で10進数⇔16進数変換を行う

$
0
0

ふと、コンソール上で10進数⇔16進数の変換を行う方法ってどんなものがあるのか、と思ったので、少し調べてみることにした。
とりあえず、以下の2つの手法が簡単に変換でき、おすすめだ。

 

1.echo+bcで対応する

echo+bcの組み合わせで、うまいこと変換させることが出来る。

●10進数→16進数

echo "obase=16; 10進数"|bc

 

●16進数→10進数

echo "ibase=16; 16進数"|bc

 

20160122_000002

[root@localhost ~]# echo "obase=16; 162"|bc
A2
[root@localhost ~]#
[root@localhost ~]# echo "ibase=16; FF"|bc
255

2.bashのprintfを使う

もしbashを使っているならば、組み込みコマンドであるprintfを使うことで簡単に変換することが出来る。

●10進数→16進数

printf %x 10進数

●16進数→10進数

printf %d 16進数

20160122_000003

[root@localhost ~]# printf %x\\n 22
16
[root@localhost ~]# printf %d\\n 0xfc
252

 

※上記例では、改行のため出力時に「\\n」をつけている

 

その他、wcalcコマンドという計算用のコマンドを使う方法もあるようだが、まぁ、インストールに面倒があるし、ただ変換するだけなら上記手法で問題無いだろう。

新しいLinuxの教科書 新しいLinuxの教科書

awkでデリミタ(区切り文字)を複数指定する

$
0
0

awkでデリミタ(区切り文字)を複数指定する場合は、「[](カギカッコ)」で囲ってやる事で-Fで指定することができる。
例えば、以下の例だと「,」と「-」で列を区切るように指定している。

awk -F'[:-]' '{…}'

20160122_000004

[root@localhost ~]# cat /tmp/test.file
aaaaa,111-11,super,66666661
bbbbb,222-22,wonder,66666662
ccccc,333-33,dorderar,66666663
ddddd,44-444,atacker,66666664
eeeee,55-55,pepsi,66666665
fffff,66-666,papet,66666666
ggggg,777-77,dagashikasi,66666667
hhhhh,888-88,goemon,66666668

[root@localhost ~]# awk -F'[,-]' '{print $2}' /tmp/test.file
111
222
333
44
55
66
777
888

[root@localhost ~]# awk -F'[,-]' '{print $3}' /tmp/test.file
11
22
33
444
55
666
77
88

 

AWK実践入門 (Software Design plus) AWK実践入門 (Software Design plus)
Viewing all 743 articles
Browse latest View live