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

sedコマンドで覚えておきたい使い方12個

$
0
0

LinuxやUNIXを使う上で、ある程度使えると非常に便利な置換コマンドが、このsedコマンドだ。
今回は、このsedコマンドで覚えておきたい使い方について紹介する。

なお、今回の置換・編集の例として、以下のファイルを用いて説明する。

[root@test-centos7 work]# cat /root/sed_test.conf
# line 1
line1=enable
# line 2
line2=disable

# line 3
line3=enable
# line 4
line4=enable

1.基本的な使い方

sedコマンドの基本的な使い方としては、以下のようにコマンドを実行することでファイル・標準出力の内容で文字列の置換を行う事だ。
なお、条件の最後に「g」を付けないと、”最初に、マッチした箇所のみ”置換するので注意。

●ファイルの内容を置換する場合

sed 's/置換前文字列/置換後文字列/g' ファイルPATH

20150729_000000

[root@test-centos7 work]# sed 's/line/gyou/g' /root/sed_test.conf
# gyou 1
gyou1=enable
# gyou 2
gyou2=disable

# gyou 3
gyou3=enable
# gyou 4
gyou4=enable

●標準出力の内容を置換する場合

コマンド | sed 's/置換前文字列/置換後文字列/g'

20150729_000001

[root@test-centos7 work]# cat /root/sed_test.conf | sed 's/line/gyou/g'
# gyou 1
gyou1=enable
# gyou 2
gyou2=disable

# gyou 3
gyou3=enable
# gyou 4
gyou4=enable

指定出来る処理内容は、以下のように非常に多い。
多いので、その中でもよく利用する処理について、個別に説明することにする。

●コメント

  • # … #移行はコメントとして取り扱う

●置換

  • c … 行をまるごと置換する
  • s … 文字列を置換する

●追加・挿入

  • a … 行を”追加”する
  • i … 行を”挿入”する

なお、複数行追加・挿入する場合は「\n」で改行を表現する。

●削除

  • d … 行を削除する
  • D … 先頭セグメントから最初の改行までを削除する

●入力

  • r ファイル名 … ファイルの内容を読み込む
  • n … パターンスペースを入力の次の行で置換
  • N … 入力の次の行をパターンスペースに追加し,改行文字を埋め込む(‘\n’ で改行として認識されるのはここで埋め込まれた改行文字だけとなる)

 ●出力

  • p … パターンスペースを標準出力に出力
  • P … パターンスペースの先頭セグメントから最初の改行までを標準出力に出力
  • | … 明白な形式でパターンスペースを標準出力に一覧表示する
  • = … 現在の行番号を 1 行として標準出力に出力(タブ文字などは対応するエスケープシーケンスとして表示され,非印字文字は 8 進数表記法で表示される)
  • w ファイル名 … ファイルにパターンスペースを追加する。w コマンドが最初に呼び出されたときにはファイルの中身はクリアされる

●ホールドスペースの利用

  • g … パターンスペースの内容をホールドスペースの内容で置換
  • G … ホールドスペースの内容をパターンスペースに追加
  • h … ホールドスペースの内容をパターンスペースの内容で置換
  • H … パターンスペースの内容をホールドスペースに追加
  • x … パターンスペースの内容とホールドスペースの内容を交換する

●グループ化

  • {コマンドリスト}

●制御構造

  • b ラベル … 指定したラベルの : コマンドに分岐
  • t ラベル … 入力行の最新の読みとりまたは t の実行以降に代入が行われている場合,指定したラベルの : コマンドに分岐
  • : ラベル … ラベル付け
  • q … 終了

なお、上記内容はこちらから引用させて頂いた。
感謝!

2.文字列を置換する

sedの基本。以下のようにコマンドを実行することで、特定の行の文字列を置換する事もできる。

●○行目にある特定の文字列を置換する場合

sed '○s/置換前文字列/置換後文字列/g'

20150729_000002

[root@test-centos7 work]# sed '4s/line/gyou/g' /root/sed_test.conf
# line 1
line1=enable
# line 2
gyou2=disable

# line 3
line3=enable
# line 4
line4=enable

●◯行目~◯行目にある特定の文字列を置換する場合

○行目~○行目までを置換する場合は、以下のように開始行と終了行をカンマで区切って記述してやると良い。

sed '○,○s/置換前文字列/置換後文字列/g'

20150729_000004

[root@test-centos7 work]# sed '4,8s/line/gyou/g' /root/sed_test.conf
# line 1
line1=enable
# line 2
gyou2=disable

# gyou 3
gyou3=enable
# gyou 4
line4=enable

●特定の文字列を含む行のみ置換する場合

特定の文字列(正規表現可)を含む行に対してのみ、置換することも出来る。

sed '/検索文字列/s/置換前文字列/置換後文字列/g'

20150731_000001

[root@test-centos7 ~]# sed '/=/s/line/gyou/g' /root/sed_test.conf
# line 1
gyou1=enable
# line 2
gyou2=disable

# line 3
gyou3=enable
# line 4
gyou4=enable
[root@test-centos7 ~]# sed '/^line/s/line/gyou/g' /root/sed_test.conf
# line 1
gyou1=enable
# line 2
gyou2=disable

# line 3
gyou3=enable
# line 4
gyou4=enable

●その行に表示される◯番目の文字列を置換する

その行で、◯番目に表示された文字列に対して処理をする場合は、以下のようにコマンドを実行する。

sed 's/置換前文字列/置換後文字列/何文字目か'

20150731_000019

[root@test-centos7 ~]# cat /root/sed_test.conf
# line 1 line 2
line1=enable
# line 2
line2=disable

# line 3
line3=enable
# line 4
line4=enable
[root@test-centos7 ~]# sed 's/line/gyou/2' /root/sed_test.conf
# line 1 gyou 2
line1=enable
# line 2
line2=disable

# line 3
line3=enable
# line 4
line4=enable

3.行を挿入する

sedでは、特定の行に対して指定した行を挿入することもできる。
挿入の場合、実行する処理に応じて「i」と「a」を使い分ける。

●指定した行番号の箇所に行を挿入する

以下のようにコマンドを実行することで、◯行目に指定した行を挿入をすることが出来る。

sed '◯i 挿入する行'

20150731_000002

[root@test-centos7 ~]# cat /root/sed_test.conf
# line 1
line1=enable
# line 2
line2=disable

# line 3
line3=enable
# line 4
line4=enable
[root@test-centos7 ~]# sed '4i testline' /root/sed_test.conf
# line 1
line1=enable
# line 2
testline
line2=disable

# line 3
line3=enable
# line 4
line4=enable

●指定した行の後ろに行を挿入する

以下のようにコマンドを実行することで、◯行目の後ろに指定した行を挿入することが出来る。

sed '◯a 挿入する行'

20150731_000003

[root@test-centos7 ~]# cat /root/sed_test.conf
# line 1
line1=enable
# line 2
line2=disable

# line 3
line3=enable
# line 4
line4=enable
[root@test-centos7 ~]# sed '4a testline' /root/sed_test.conf
# line 1
line1=enable
# line 2
line2=disable
testline

# line 3
line3=enable
# line 4
line4=enable

●指定した複数の各行の前、後ろに行を挿入する

指定した行の範囲に対し、挿入を行う事も出来る。

sed '◯,◯i 挿入する行' #前に挿入する場合
sed '◯,◯a 挿入する行' #後に挿入する場合

20150731_000004

[root@test-centos7 ~]# sed '1,4i testline' /root/sed_test.conf
testline
# line 1
testline
line1=enable
testline
# line 2
testline
line2=disable

# line 3
line3=enable
# line 4
line4=enable
[root@test-centos7 ~]# sed '1,4a testline' /root/sed_test.conf
# line 1
testline
line1=enable
testline
# line 2
testline
line2=disable
testline

# line 3
line3=enable
# line 4
line4=enable

●指定したキーワードを持つ行の前・後に行を挿入する

キーワードを指定して、その行の前・後に行を挿入することも出来る。

sed '/キーワード/i 挿入する行' #前に挿入する場合
sed '/キーワード/a 挿入する行' #後に挿入する場合

20150731_000005

[root@test-centos7 ~]# cat /root/sed_test.conf
# line 1
line1=enable
# line 2
line2=disable

# line 3
line3=enable
# line 4
line4=enable
[root@test-centos7 ~]# sed '/line3/i testline' /root/sed_test.conf
# line 1
line1=enable
# line 2
line2=disable

# line 3
testline
line3=enable
# line 4
line4=enable
[root@test-centos7 ~]# sed '/line3/a testline' /root/sed_test.conf
# line 1
line1=enable
# line 2
line2=disable

# line 3
line3=enable
testline
# line 4
line4=enable

4.行を削除する

指定した行を削除して表示させることも出来る。

●◯行目を削除する

削除する行が◯行目と決まっている場合、以下のようにコマンドを実行する。

sed '◯d'

20150731_000006

[root@test-centos7 ~]# cat /root/sed_test.conf
# line 1
line1=enable
# line 2
line2=disable

# line 3
line3=enable
# line 4
line4=enable
[root@test-centos7 ~]# sed '4d' /root/sed_test.conf
# line 1
line1=enable
# line 2

# line 3
line3=enable
# line 4
line4=enable

●◯行目~◯行目を削除する

◯行目~◯行目を削除する場合は、以下のようにする。

sed '◯,◯d'

20150731_000007

[root@test-centos7 ~]# cat /root/sed_test.conf
# line 1
line1=enable
# line 2
line2=disable

# line 3
line3=enable
# line 4
line4=enable
[root@test-centos7 ~]# sed '1,4d' /root/sed_test.conf

# line 3
line3=enable
# line 4
line4=enable

●決まったキーワードを持つ行を除外する

特定のキーワードを持つ行を削除する場合は、以下のようにする。

sed '/キーワード/d'

20150731_000008

[root@test-centos7 ~]# cat /root/sed_test.conf
# line 1
line1=enable
# line 2
line2=disable

# line 3
line3=enable
# line 4
line4=enable
[root@test-centos7 ~]# sed '/line2/d' /root/sed_test.conf
# line 1
line1=enable
# line 2

# line 3
line3=enable
# line 4
line4=enable

5.行の内容を上書きする

指定した行の内容を置換ではなく、上書きすることも出来る。

●◯行目の内容を上書きする

以下のようにコマンドを実行することで、指定した行の内容を上書きして置き換える事が出来る。

sed '◯c 置き換え後の行'

20150731_000009

[root@test-centos7 ~]# cat /root/sed_test.conf
# line 1
line1=enable
# line 2
line2=disable

# line 3
line3=enable
# line 4
line4=enable
[root@test-centos7 ~]# sed '4c testline' /root/sed_test.conf
# line 1
line1=enable
# line 2
testline

# line 3
line3=enable
# line 4
line4=enable

●特定のキーワードを持つ行を上書きする

もちろん、特定のキーワードを持つ行を上書きすることも出来る。

sed '/キーワード/c 置き換え後の行'

20150731_000010

[root@test-centos7 ~]# cat /root/sed_test.conf
# line 1
line1=enable
# line 2
line2=disable

# line 3
line3=enable
# line 4
line4=enable
[root@test-centos7 ~]# sed '/line3/c testline' /root/sed_test.conf
# line 1
line1=enable
# line 2
line2=disable

# line 3
testline
# line 4
line4=enable

6.ファイルの内容を上書きする

sedで編集した内容をファイルに上書きしたい場合もあるだろう。
そんなときは、「-i」オプションを付与すると上書きをすることが出来る。

sed -i '置換条件' ファイルPATH

20150731_000013

[root@test-centos7 ~]# cat /root/sed_test.conf
# line 1
line1=enable
# line 2
line2=disable

# line 3
line3=enable
# line 4
line4=enable
[root@test-centos7 ~]# sed 's/line 1/line #/g' /root/sed_test.conf
# line #
line1=enable
# line 2
line2=disable

# line 3
line3=enable
# line 4
line4=enable
[root@test-centos7 ~]# sed -i 's/line 1/line #/g' /root/sed_test.conf
[root@test-centos7 ~]# cat /root/sed_test.conf
# line #
line1=enable
# line 2
line2=disable

# line 3
line3=enable
# line 4
line4=enable

 

保存時に直前の状態のバックアップを取得させることも出来る。

sed -i.バックアップファイルの末尾に付与する文字列 '置換条件' ファイルPATH

20150731_000014

[root@test-centos7 ~]# cat /root/sed_test.conf
# line #
line1=enable
# line 2
line2=disable

# line 3
line3=enable
# line 4
line4=enable
[root@test-centos7 ~]# sed -i.$(date +%Y%m%d) 's/line 2/line #/g' /root/sed_test.conf
[root@test-centos7 ~]# cat /root/sed_test.conf.20150731
# line #
line1=enable
# line 2
line2=disable

# line 3
line3=enable
# line 4
line4=enable
[root@test-centos7 ~]# cat /root/sed_test.conf
# line #
line1=enable
# line #
line2=disable

# line 3
line3=enable
# line 4
line4=enable

なお、このオプションはGNU拡張のコマンドじゃないと用意されていないので注意。
HP-UX等の場合だと使えないので、一度リダイレクトなどで別のファイルに書き出してから上書きすることをお勧めしたい。

7.複数の置換条件を適用する

複数の置換条件を使用する場合は、「-e」オプションでそれぞれの置換条件を指定してあげると良い。

sed -e '置換条件' -e '置換条件' ...

20150731_000015

[root@test-centos7 ~]# cat /root/sed_test.conf
# line 1
line1=enable
# line 2
line2=disable

# line 3
line3=enable
# line 4
line4=enable
[root@test-centos7 ~]# sed -e 's/line/gyou/g' -e '5c aaaaaaa' /root/sed_test.conf
# gyou 1
gyou1=enable
# gyou 2
gyou2=disable
aaaaaaa
# gyou 3
gyou3=enable
# gyou 4
gyou4=enable

8. ファイルに書いた置換条件を読み込む

「-f」オプションを使用することで、外部ファイルに記述した置換条件を読み込んで実行することが出来る。

sed -f スクリプトファイルPATH

20150731_000016

[root@test-centos7 ~]# cat /root/sed_test.conf
# line 1
line1=enable
# line 2
line2=disable

# line 3
line3=enable
# line 4
line4=enable
[root@test-centos7 ~]# cat /root/sed_script
s/line/gyou/g
5c aaaaaaa
[root@test-centos7 ~]# sed -f /root/sed_script /root/sed_test.conf
# gyou 1
gyou1=enable
# gyou 2
gyou2=disable
aaaaaaa
# gyou 3
gyou3=enable
# gyou 4
gyou4=enable

9.小文字/大文字の変換をする

GNU拡張版のsedであれば、以下のようにコマンドを実行することで小文字⇔大文字の変換を行う事が出来る。

●小文字→大文字の場合

sed 's/\(.*\)/\U\1/'

20150731_000017

[root@test-centos7 ~]# cat /root/sed_test.conf
# line 1
line1=enable
# line 2
line2=disable

# line 3
line3=enable
# line 4
line4=enable
[root@test-centos7 ~]# sed 's/\(.*\)/\U\1/' /root/sed_test.conf
# LINE 1
LINE1=ENABLE
# LINE 2
LINE2=DISABLE

# LINE 3
LINE3=ENABLE
# LINE 4
LINE4=ENABLE

●大文字→小文字の場合

sed 's/\(.*\)/\L\1/'

20150731_000018

[root@test-centos7 ~]# cat /root/sed_test.conf
# LINE 1
LINE1=ENABLE
# LINE 2
LINE2=DISABLE

# LINE 3
LINE3=ENABLE
# LINE 4
LINE4=ENABLE
[root@test-centos7 ~]# sed 's/\(.*\)/\L\1/' /root/sed_test.conf
# line 1
line1=enable
# line 2
line2=disable

# line 3
line3=enable
# line 4
line4=enable

 

もしPosix標準のsedしか使えない場合は、以下のようにコマンドを実行することで変換出来る。

sed "y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/" # 小文字→大文字の場合
sed "y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/" # 大文字→小文字の場合

10.置換にコマンドの実行結果を利用する

sedでの置換にコマンドの実行結果を利用する場合は、処理を「'(シングルクォーテーション)」で囲わず、「”(ダブルクォーテーション)」か特に囲まないで、コマンドの実行箇所だけを「`(バッククォート)」で囲んで記述するといいだろう。

20150220_000000

$ cat test.hostname
hostname
HOSTNAME
TESTNAME
$
$ # シングルォーテーションだと、置換されない
$ sed -e 's/hostname/`hostname`/g' ./test.hostname
`hostname`
HOSTNAME
TESTNAME
$
$ # ダブルクォーテーションだと、置換される
$ sed -e "s/hostname/`hostname`/g" ./test.hostname
test-centos
HOSTNAME
TESTNAME
$
$ # 処理を囲まなくても置換される
$ sed -e s/hostname/`hostname`/g ./test.hostname
test-centos
HOSTNAME
TESTNAME
$

なお、sshコマンド経由でsedを実行させる場合は、sedコマンドの処理自体をシングルクォーテーションで括る必要があるので注意。

11.ダブルクォーテーション・シングルクォーテーションで囲まれた文字列に対して処理を行う

sedの使い方というよりも正規表現の書き方になりそうだが、ダブルクォーテーション・シングルクォーテーションで囲まれた文字列に対し処理を行う場合、以下のようにコマンドを実行する。

●ダブルクォーテーションの場合

sed 's/"\([^"]*\)"/"置換後の値"/' 対象のファイルPATH
[root@test-centos7 work]# cat /work/test.txt
testline1="test1"
testline2="test2"

testline3='test3'
testline4='test4'
[root@test-centos7 work]# sed 's/"\([^"]*\)"/"replace"/' /work/test.txt
testline1="replace"
testline2="replace"

testline3='test3'
testline4='test4'

●シングルクォーテーションの場合

sed 's/"\([^"]*\)"/"置換後の値"/' 対象のファイルPATH
[root@test-centos7 work]# cat /work/test.txt
testline1="test1"
testline2="test2"

testline3='test3'
testline4='test4'
[root@test-centos7 work]# sed "s/'\([^']*\)'/'replace'/" /work/test.txt
testline1="test1"
testline2="test2"

testline3='replace'
testline4='replace'

20150604_000000

12.ログから特定の時間帯の内容を抜き出す

以下のようにコマンドを実行することで、特定の時間帯のログを出力させることも出来る。

awk -F - '"開始時間" < $1 && $1 <= "終了時間"' /抽出を行うログのPATH

20150405_000002

 

パターン・使い道が多すぎて、とりあえず今回はこれだけ。
sedコマンドはまだまだ便利な方法がある(というか、多分こんな程度ではない…)、これからも勉強していかないとなぁ。。。

覚えて便利 いますぐ使える!シェルスクリプトシンプルレシピ54 覚えて便利 いますぐ使える!シェルスクリプトシンプルレシピ54

Linuxのlogrotateを手動実行させる

$
0
0

Linuxのlogrotateを手動実行する場合、ただ実行コマンド(“/usr/sbin/logrotate /etc/logrotate.conf”)を実行しただけではログローテーションは行われない。
手動でのローテーションを行う場合は、以下のファイルに記述されている各ログの日付を過去日付にしてあげる必要がある。

●Debian/Ubuntuの場合

「/var/lib/logrotate/status」というファイルに各ログで最後にログローテーションした日付が記述されている。

test@ubuntu-server:~$ cat /var/lib/logrotate/status
logrotate state -- version 2
"/var/log/syslog" 2015-7-24-6:25:2
"/var/log/dpkg.log" 2015-7-1-6:25:2
"/var/log/auth.log" 2015-7-19-6:25:3
"/var/log/apt/term.log" 2015-7-1-6:25:2
"/var/log/ppp-connect-errors" 2015-7-24-6:0:0
"/var/log/apt/history.log" 2015-7-1-6:25:2
"/var/log/alternatives.log" 2015-7-1-6:25:2
"/var/log/debug" 2015-7-24-6:0:0
"/var/log/mail.log" 2015-7-24-6:0:0
"/var/log/kern.log" 2015-7-13-6:25:2
"/var/log/aptitude" 2015-7-24-6:0:0
"/var/log/ufw.log" 2015-7-24-6:0:0
"/var/log/daemon.log" 2015-7-24-6:0:0
"/var/log/wtmp" 2015-7-1-6:25:2
"/var/log/mail.warn" 2015-7-24-6:0:0
"/var/log/btmp" 2015-7-1-6:25:2
"/var/log/lpr.log" 2015-7-24-6:0:0
"/var/log/mail.err" 2015-7-24-6:0:0
"/var/log/upstart/*.log" 2015-7-24-6:0:0
"/var/log/user.log" 2015-7-24-6:0:0
"/var/log/mail.info" 2015-7-24-6:0:0
"/var/log/cron.log" 2015-7-24-6:0:0
"/var/log/messages" 2015-7-24-6:0:0

●RHEL系の場合

RHEL系の場合は、「/var/lib/logrotate.status」というファイルに各ログで最後にログローテーションした日付が記述されている。

[root@test-centos7 ~]# cat /var/lib/logrotate.status
logrotate state -- version 2
"/var/log/yum.log" 2015-5-29-3:6:1
"/var/log/httpd/ssl_access_log" 2015-7-12-3:0:0
"/var/log/httpd/*log" 2015-6-14-3:0:0
"/var/log/httpd/error_log" 2015-7-26-3:50:1
"/var/log/httpd/ssl_error_log" 2015-7-26-3:50:1
"/var/log/wtmp" 2014-12-19-6:0:0
"/var/log/chrony/*.log" 2015-6-29-3:0:0
"/var/log/spooler" 2015-7-26-3:50:1
"/var/log/btmp" 2015-7-1-3:21:1
"/var/log/iscsiuio.log" 2015-6-29-3:0:0
"/var/log/maillog" 2015-7-26-3:50:1
"/var/log/httpd/ssl_request_log" 2015-7-12-3:0:0
"/var/log/wpa_supplicant.log" 2014-12-19-6:0:0
"/var/log/secure" 2015-7-26-3:50:1
"/var/log/ppp/connect-errors" 2014-12-19-6:0:0
"/var/log/messages" 2015-7-26-3:50:1
"/var/log/httpd/access_log" 2015-7-26-3:50:1
"/var/log/cron" 2015-7-26-3:50:1

 

後は、ローテーションさせたいログの日付を変更し、以下のコマンドを実行すれば良い。

/usr/sbin/logrotate /etc/logrotate.conf
rsyslog 実践ログ管理入門 rsyslog 実践ログ管理入門

~2015年8月15日までお休みします

$
0
0

引越しするのと、仕事が忙しくなってきてるので、8月15日くらいまで更新お休みします。

sedで特定の文字列~文字列間を置換する

$
0
0

sedでは、ある文字列~文字列間の行を置換する、と言った指定をすることが出来る。

sed '/文字列(開始)/,/文字列(終了)/s/○○○/●●●/g' 対象のファイルPATH

20150910_000000

[root@test-centos7 ~]# cat test.txt
testline1="test1"
testline2="test2"

testline3='test7'
testline4='test4'

testline5 test5
testline6 = test6
[root@test-centos7 ~]#
[root@test-centos7 ~]# sed '/line2/,/line3/s/test/aaaa/g' test.txt
testline1="test1"
aaaaline2="aaaa2"

aaaaline3='aaaa7'
testline4='test4'

testline5 test5
testline6 = test6

もちろん、行そのものの入れ替えをすることも可能だ。

[root@test-centos7 ~]# sed '/line2/,/line3/caaaa' test.txt
testline1="test1"
aaaa
testline4='test4'

testline5 test5
testline6 = test6

個人的には、ソースコードなどに記述されている文章を入れ替えたりする際などに役に立つので、結構便利だったりする。

UNIXシェルスクリプト マスターピース132 UNIXシェルスクリプト マスターピース132

uniqコマンドで覚えておきたい使い方6個

$
0
0

uniqコマンドは、Linux/UNIXで使用される、重複した行を圧縮して出力してくれるコマンドだ。
今回は、このコマンドについて覚えておきたい使い方についてを紹介する。

1.基本的な使い方

基本的には、以下のように使用することで標準出力の内容から重複行を圧縮して表示させることが出来る。

20150913_000000

[root@test-centos7 ~]# cat /test/test3.txt
aaaaa
aaaaa
aaaaa
bbbbb
bbbbb
bbbbb
bbbbb
bbbbb
ccccc
ccccc

[root@test-centos7 ~]# cat /test/test3.txt | uniq
aaaaa
bbbbb
ccccc

この時注意したいのが、「連続していない行」の場合は圧縮しないという点だ。 たとえば、以下のような状態でuniqコマンドを実行しても、重複した行は残ってしまう。

[root@test-centos7 ~]# cat /test/test4.txt
aaaaa
aaaaa
bbbbb
bbbbb
aaaaa
bbbbb
bbbbb
ccccc
ccccc
bbbbb

[root@test-centos7 ~]# cat /test/test4.txt | uniq
aaaaa
bbbbb
aaaaa
bbbbb
ccccc
bbbbb

2.重複している行の数をカウントする

「-c」オプションを使用することで、重複行が何行あったのかを左はじに表示してくれる。

20150916_000000

[root@test-centos7 ~]# cat /test/test3.txt
aaaaa
aaaaa
aaaaa
bbbbb
bbbbb
bbbbb
bbbbb
bbbbb
ccccc
ccccc

[root@test-centos7 ~]# cat /test/test3.txt | uniq -c
      3 aaaaa
      5 bbbbb
      2 ccccc
      1

3.重複した行・重複していない行だけを表示させる

重複した行、重複していない行だけを表示させることも出来る。
重複している行のみを出力させる場合は「-d」を、重複のない(ユニークな)行をのみを出力させる場合は「-u」オプションを付与する。

20150916_000001

[root@test-centos7 ~]# cat /test/test3.txt
aaaaa
aaaaa
aaaaa
aaaa1
bbbbb
bbbbb
bbbbb
bbbbb
bbbbb
bbbb2
ccccc
ccccc

[root@test-centos7 ~]# cat /test/test3.txt | uniq -d
aaaaa
bbbbb
ccccc
[root@test-centos7 ~]# cat /test/test3.txt | uniq -u
aaaa1
bbbb2

なお、「-d」ではなく「-D」を使用すると、重複している行を圧縮せずに表示させることが出来る。

20150916_000002

[root@test-centos7 ~]# cat /test/test3.txt
aaaaa
aaaaa
aaaaa
aaaa1
bbbbb
bbbbb
bbbbb
bbbbb
bbbbb
bbbb2
ccccc
ccccc

[root@test-centos7 ~]# cat /test/test3.txt | uniq -D
aaaaa
aaaaa
aaaaa
bbbbb
bbbbb
bbbbb
bbbbb
bbbbb
ccccc
ccccc

4.大文字・小文字を区別せずに判断する

大文字・小文字を区別せずに重複行か否かを判断させる場合は、「-i」オプションを使用する。

20150919_000000

[root@test-centos7 ~]# cat /test/test4.txt
aaaaa
AAAAA
aaaaa
bbbbb
bbbbb
BBBBB
bbbbb
ccccc
CCCCC
ccccc
[root@test-centos7 ~]# cat /test/test4.txt | uniq
aaaaa
AAAAA
aaaaa
bbbbb
BBBBB
bbbbb
ccccc
CCCCC
ccccc
[root@test-centos7 ~]# cat /test/test4.txt | uniq -i
aaaaa
bbbbb
ccccc

5.指定した項目数、文字数をスキップして重複しているかどうかを判断する

各行で指定した項目数、文字数をスキップして、その範囲内で重複しているかどうかを判断させることも出来る。
スキップする項目数は「-f」、文字数は「-s」で指定出来る。

20150919_000001

[root@test-centos7 ~]# cat /test/test5.txt
aaaaa bbbbb
aabbb bbbbb
ccbbb ccccc
ddbbb ccccc
bbbbb ccccc
eeeeb ddddd
[root@test-centos7 ~]#
[root@test-centos7 ~]# # 項目をスキップする
[root@test-centos7 ~]# cat /test/test5.txt | uniq -f 1
aaaaa bbbbb
ccbbb ccccc
eeeeb ddddd
[root@test-centos7 ~]#
[root@test-centos7 ~]# # 文字をスキップする
[root@test-centos7 ~]# cat /test/test5.txt | uniq -s 6
aaaaa bbbbb
ccbbb ccccc
eeeeb ddddd
[root@test-centos7 ~]#
[root@test-centos7 ~]# # 頭から2文字スキップし、3文字で重複を確認する
[root@test-centos7 ~]# cat /test/test5.txt | uniq -s 2 -w 3
aaaaa bbbbb
aabbb bbbbb
eeeeb ddddd

6.重複しているかどうか判断する文字数を指定する

先の項目でも少し触れているが、「-w」オプションを付与することで重複しているかどうか判断する文字数を指定することが出来る。

20150919_000002

[root@test-centos7 ~]# cat /test/test5.txt
aaaaa bbbbb
aabbb bbbbb
ccbbb ccccc
ddbbb ccccc
bbbbb ccccc
eeeeb ddddd
[root@test-centos7 ~]#
[root@test-centos7 ~]# cat /test/test5.txt | uniq -w 2
aaaaa bbbbb
ccbbb ccccc
ddbbb ccccc
bbbbb ccccc
eeeeb ddddd
[改訂新版] シェルスクリプト基本リファレンス  --#!/bin/shで、ここまでできる (WEB+DB PRESS plus) [改訂新版] シェルスクリプト基本リファレンス  --#!/bin/shで、ここまでできる (WEB+DB PRESS plus)

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

$
0
0

Linux/UNIXでよく使用される、出力される内容を並び替えするsortコマンド。
今回は、このsortコマンドで覚えておきたい使い方についてを紹介する。

1.基本的な使い方

基本的には、以下のようにコマンドを実行することでその出力内容を並び替える事が出来る。

20150923_000000

[root@test-centos7 ~]# cat /work/test5.txt
5 eeeee
1 aaaaa
4 ddddd
2 bbbbb
6 fffff
3 ccccc
[root@test-centos7 ~]# cat /work/test5.txt | sort
1 aaaaa
2 bbbbb
3 ccccc
4 ddddd
5 eeeee
6 fffff

2.文字列を数字として並び替えを行う

通常、sortコマンドで並び替えを行う場合、文字列として並び替えされてしまう。
それを数字として並び替える場合、「-n」オプションを付与する。

20150923_000001

[root@test-centos7 ~]# cat /work/test5.txt
5 eeeee
1 aaaaa
9 iiiii
4 ddddd
8 hhhhh
10 jjjjj
2 bbbbb
6 fffff
7 ggggg
3 ccccc
[root@test-centos7 ~]# cat /work/test5.txt | sort
1 aaaaa
10 jjjjj
2 bbbbb
3 ccccc
4 ddddd
5 eeeee
6 fffff
7 ggggg
8 hhhhh
9 iiiii
[root@test-centos7 ~]# cat /work/test5.txt | sort -n
1 aaaaa
2 bbbbb
3 ccccc
4 ddddd
5 eeeee
6 fffff
7 ggggg
8 hhhhh
9 iiiii
10 jjjjj

3.逆順で並び替えを行う

並び替えを逆順(降順)で行う場合は、「-r」オプションを付与する。

20150923_000003

[root@test-centos7 ~]# cat /work/test5.txt
5 eeeee
1 aaaaa
9 iiiii
4 ddddd
8 hhhhh
10 jjjjj
2 bbbbb
6 fffff
7 ggggg
3 ccccc
[root@test-centos7 ~]# cat /work/test5.txt | sort -n
1 aaaaa
2 bbbbb
3 ccccc
4 ddddd
5 eeeee
6 fffff
7 ggggg
8 hhhhh
9 iiiii
10 jjjjj
[root@test-centos7 ~]# cat /work/test5.txt | sort -nr
10 jjjjj
9 iiiii
8 hhhhh
7 ggggg
6 fffff
5 eeeee
4 ddddd
3 ccccc
2 bbbbb
1 aaaaa

4.並び替えを行う列を指定する

並び替えを行う列を指定する場合は、「-k」オプションを用いてその列を指定する事も出来る。複数指定する場合は、優先順位ごとに「,」で区切る。
例えば、以下の例では3列目で並び替えを実施している。

20150923_000006

[root@test-centos7 ~]# cat /work/test5.txt
5 eeeee 9
1 aaaaa 10
9 iiiii 1
4 ddddd 3
8 hhhhh 2
10 jjjjj 5
2 bbbbb 4
6 fffff 6
7 ggggg 8
3 ccccc 7
[root@test-centos7 ~]# cat /work/test5.txt | sort -n
1 aaaaa 10
2 bbbbb 4
3 ccccc 7
4 ddddd 3
5 eeeee 9
6 fffff 6
7 ggggg 8
8 hhhhh 2
9 iiiii 1
10 jjjjj 5
[root@test-centos7 ~]# cat /work/test5.txt | sort -n -k3
9 iiiii 1
8 hhhhh 2
4 ddddd 3
2 bbbbb 4
10 jjjjj 5
6 fffff 6
3 ccccc 7
7 ggggg 8
5 eeeee 9
1 aaaaa 10

なお、通常であれば各列の区切りはスペースやTabとなっているが、特定の文字列(例えばカンマなど)で列が区切られている場合は、「-t」オプションで指定することが出来る。
以下の例では、「-t」で「,(カンマ)」区切りを指定している。

20150923_000007

[root@test-centos7 ~]# cat /work/test5_1.txt
5,eeeee,9
1,aaaaa,10
9,iiiii,1
4,ddddd,3
8,hhhhh,2
10,jjjjj,5
2,bbbbb,4
6,fffff,6
7,ggggg,8
3,ccccc,7
[root@test-centos7 ~]# cat /work/test5_1.txt | sort -nk3 -t,
9,iiiii,1
8,hhhhh,2
4,ddddd,3
2,bbbbb,4
10,jjjjj,5
6,fffff,6
3,ccccc,7
7,ggggg,8
5,eeeee,9
1,aaaaa,10

5.大文字・小文字の区別をしない

sortコマンドでは、通常だとアルファベットの大文字、小文字を区別して並び替えを行う。
これを大文字、小文字の区別なく並び替えさせる場合は、「-f」オプションを付与する

20150923_000008

[root@test-centos7 ~]# cat /work/test5_2.txt
aaaaaa
bbbbbb
DDDDDD
AAAAAA
cccccc
dddddd
eeeeee
CCCCCC
[root@test-centos7 ~]# cat /work/test5_2.txt | sort
AAAAAA
CCCCCC
DDDDDD
aaaaaa
bbbbbb
cccccc
dddddd
eeeeee
[root@test-centos7 ~]# cat /work/test5_2.txt | sort -f
AAAAAA
aaaaaa
bbbbbb
CCCCCC
cccccc
DDDDDD
dddddd
eeeeee

6.バイト数(KB、MB、GB etc…)を並び替えする

人間が読みやすい状態で出力されたバイト数を並び替えるには、「-h」オプションを利用する。

20150923_000009

[root@test-centos7 ~]# du -h /etc | head
24K     /etc/pki/rpm-gpg
176K    /etc/pki/ca-trust/extracted/java
312K    /etc/pki/ca-trust/extracted/openssl
600K    /etc/pki/ca-trust/extracted/pem
1.1M    /etc/pki/ca-trust/extracted
0       /etc/pki/ca-trust/source/anchors
0       /etc/pki/ca-trust/source/blacklist
4.0K    /etc/pki/ca-trust/source
1.1M    /etc/pki/ca-trust
0       /etc/pki/java
[root@test-centos7 ~]# du -h /etc | sort -hr | head
22M     /etc
11M     /etc/selinux/targeted
11M     /etc/selinux
5.8M    /etc/udev
5.6M    /etc/selinux/targeted/modules/active
5.6M    /etc/selinux/targeted/modules
4.8M    /etc/selinux/targeted/modules/active/modules
3.7M    /etc/selinux/targeted/policy
1.8M    /etc/selinux/targeted/contexts
1.7M    /etc/selinux/targeted/contexts/files

※なお、findとlsを組み合わせた出力をsortしたところ、うまく出力されなかった。
awkでサイズを左端にするとうまく動作するようだが、理由は不明。

7.sort時に重複している行を圧縮する

sort時に重複している行を削除する場合は、「-u」オプションを使用する。

20150923_000010

[root@test-centos7 ~]# cat /work/test5_3.txt | sort -n
1 aaaaa 10
1 aaaaa 10
2 bbbbb 4
3 ccccc 7
4 ddddd 3
4 ddddd 3
5 eeeee 9
6 fffff 6
7 ggggg 8
7 ggggg 8
8 hhhhh 2
9 iiiii 1
10 jjjjj 5
10 jjjjj 5
[root@test-centos7 ~]# cat /work/test5_3.txt | sort -un
1 aaaaa 10
2 bbbbb 4
3 ccccc 7
4 ddddd 3
5 eeeee 9
6 fffff 6
7 ggggg 8
8 hhhhh 2
9 iiiii 1
10 jjjjj 5

8.sort済のファイルに結果をマージする

すでにsort済の各ファイルをマージする場合は、「-m」オプションで行う事が出来る。

20150923_000012

[root@test-centos7 ~]# cat /work/test5_4.txt
1 aaaaa 10
2 bbbbb 4
3 ccccc 7
4 ddddd 3
5 eeeee 9
6 fffff 6
7 ggggg 8
8 hhhhh 2
9 iiiii 1
10 jjjjj 5
[root@test-centos7 ~]# cat /work/test5_5.txt
5 dadadad
9 aaaaaaaaa
11 dadadadadada
12 cccccccccccc
[root@test-centos7 ~]# sort -nm /work/test5_4.txt /work/test5_5.txt
1 aaaaa 10
2 bbbbb 4
3 ccccc 7
4 ddddd 3
5 dadadad
5 eeeee 9
6 fffff 6
7 ggggg 8
8 hhhhh 2
9 aaaaaaaaa
9 iiiii 1
10 jjjjj 5
11 dadadadadada
12 cccccccccccc

9.ファイルが順番どおりに並び替えられているか確認する

「-c」オプションを使用すると、そのファイルがソート済かどうかを確認することが出来る。

20150924_000000

[root@test-centos7 ~]# cat /work/test5_3.txt
7 ggggg 8
5 eeeee 9
1 aaaaa 10
10 jjjjj 5
9 iiiii 1
4 ddddd 3
8 hhhhh 2
1 aaaaa 10
10 jjjjj 5
2 bbbbb 4
4 ddddd 3
6 fffff 6
7 ggggg 8
3 ccccc 7
[root@test-centos7 ~]# sort -c /work/test5_3.txt
sort: /work/test5_3.txt:2: 順序が不規則: 5 eeeee 9
[root@test-centos7 ~]# sort /work/test5_3.txt | sort -c
シェルスクリプトマガジン vol.30 シェルスクリプトマガジン vol.30

Linux・UNIXでExcelのフィルタのように、ファイルから〇〇以上、〇〇以下で行を抽出する方法

$
0
0

LinuxやUNIXで、Excelのフィルタ機能のように特定の列で〇〇以上、〇〇以下といった指定方法で行を抽出する場合は、awkを使うとカンタンだ。
awkで特定列の値が〇〇以上の行を指定する場合は、以下のように指定する。

awk '列 >= 条件' 対象ファイル

 

複数条件を指定する場合は、以下のように「&&」で繋げる(orの場合は、「||」で繋げる)。
例えば、特定列の値が〇〇以上、〇〇以下といった指定をする場合は、以下のようにする。

awk '列 >= 条件 && 列 <= 条件' 対象ファイル

20150925_000000

[root@test-centos7 ~]# cat /work/test5_7.txt
1 aaaaa 10
2 bbbbb 4
3 ccccc 7
4 ddddd 3
5 eeeee 9
6 fffff 6
7 ggggg 8
8 hhhhh 2
9 iiiii 1
10 jjjjj 5
[root@test-centos7 ~]# awk '$1 >=3' /work/test5_7.txt
3 ccccc 7
4 ddddd 3
5 eeeee 9
6 fffff 6
7 ggggg 8
8 hhhhh 2
9 iiiii 1
10 jjjjj 5
[root@test-centos7 ~]# awk '$1 >=3 && $1 <=7' /work/test5_7.txt
3 ccccc 7
4 ddddd 3
5 eeeee 9
6 fffff 6
7 ggggg 8

もちろん、特定列の値を指定することも出来る。

awk '列 == 条件' 対象ファイル

20150925_000001

[root@test-centos7 ~]# cat /work/test5_7.txt
1 aaaaa 10
2 bbbbb 4
3 ccccc 7
4 ddddd 3
5 eeeee 9
6 fffff 6
7 ggggg 8
8 hhhhh 2
9 iiiii 1
10 jjjjj 5
[root@test-centos7 ~]# awk '$2=="ccccc"' /work/test5_7.txt
3 ccccc 7

このように、Linux/UNIXのコマンドライン上でExcelのフィルタのような抽出をするなら、awkを使えばカンタンに行う事が出来る。

2015/10/01 追記

なお、条件部分は以下のように記述することも出来る。
こちらのほうが、同一列内で複数条件をor検索する際に楽なので、状況に応じて使い分けた方がいいかも。

awk '列 ~ /条件/ 対象ファイル'

20151001_000004

[root@test-centos7 ~]# cat /work/test5_7.txt
1 aaaaa 10
2 bbbbb 4
3 ccccc 7
4 ddddd 3
5 eeeee 9
6 fffff 6
7 ggggg 8
8 hhhhh 2
9 iiiii 1
10 jjjjj 5
[root@test-centos7 ~]#
[root@test-centos7 ~]# # こちらの書き方でも抽出出来る
[root@test-centos7 ~]# awk '$2 ~ /ccccc/' /work/test5_7.txt
3 ccccc 7
[root@test-centos7 ~]# # 複数条件がある場合は、「/~/」の間でパイプ区切りで記述する。
[root@test-centos7 ~]# awk '$2 ~ /ccccc|aaaaa/' /work/test5_7.txt
1 aaaaa 10
3 ccccc 7

 

AWK実践入門 AWK実践入門

awkで[](カギカッコ)内の値に応じて行を抽出する

$
0
0

仕事で、Apacheのログ・ファイルから[](カギカッコ)内に記述されている応答時間で、時間のかかっているログのみを抽出するといった対応があった。
で、とりあえず〇〇秒以上のログだけを抽出するような対応をしたので、その備忘。

対応としては、以下のようにデリミタに[](カギカッコ)を指定して、その中の値が〇〇以上のログだけを抽出するようにした。

awk -F '[][]' '$4 >= 〇〇' ログファイルPATH

20150925_000002

[root@test-centos7 ~]# cat /var/log/httpd/access_log-20150906
::1 - - [02/Aug/2015:15:33:22 +0900] "OPTIONS * HTTP/1.0" 200 - "-" "Apache/2.4.6 (CentOS) OpenSSL/1.0.1e-fips PHP/5.4.16 (internal dummy connection)" [0]
::1 - - [02/Aug/2015:15:33:22 +0900] "OPTIONS * HTTP/1.0" 200 - "-" "Apache/2.4.6 (CentOS) OpenSSL/1.0.1e-fips PHP/5.4.16 (internal dummy connection)" [20]
::1 - - [02/Aug/2015:15:33:22 +0900] "OPTIONS * HTTP/1.0" 200 - "-" "Apache/2.4.6 (CentOS) OpenSSL/1.0.1e-fips PHP/5.4.16 (internal dummy connection)" [0]
::1 - - [02/Aug/2015:15:33:22 +0900] "OPTIONS * HTTP/1.0" 200 - "-" "Apache/2.4.6 (CentOS) OpenSSL/1.0.1e-fips PHP/5.4.16 (internal dummy connection)" [50]
::1 - - [02/Aug/2015:15:33:22 +0900] "OPTIONS * HTTP/1.0" 200 - "-" "Apache/2.4.6 (CentOS) OpenSSL/1.0.1e-fips PHP/5.4.16 (internal dummy connection)" [10]
[root@test-centos7 ~]# awk -F '[][]' '$4 >= 20' /var/log/httpd/access_log-20150906
::1 - - [02/Aug/2015:15:33:22 +0900] "OPTIONS * HTTP/1.0" 200 - "-" "Apache/2.4.6 (CentOS) OpenSSL/1.0.1e-fips PHP/5.4.16 (internal dummy connection)" [20]
::1 - - [02/Aug/2015:15:33:22 +0900] "OPTIONS * HTTP/1.0" 200 - "-" "Apache/2.4.6 (CentOS) OpenSSL/1.0.1e-fips PHP/5.4.16 (internal dummy connection)" [50]

 

AWK実践入門 AWK実践入門

PowerShellで対象URLのステータス(200,404etc…)を取得する

$
0
0

仕事で、PowerShellから対象URLのステータス状態(200とか404とか)を取得する必要があったので、その備忘。
PowerShellでその辺りの情報を取得する場合は、以下のように記述する。

$url = "対象URL"
[System.Net.HttpWebRequest]$REQUEST = [System.Net.WebRequest]::Create($url)
$RESPONSE = $REQUEST.GetResponse()
$RESPONSE.Close()
[int]$RESPONSE.StatusCode

対象URLの所は、適当に引数等を指定してスクリプト化すると良いだろう。

動くサンプルで学べる Windows PowerShell コマンド&スクリプティングガイド PowerShell 4.0対応 動くサンプルで学べる Windows PowerShell コマンド&スクリプティングガイド PowerShell 4.0対応

LinuxのCUIでアメリカ市場の株価チェックを出来る『Mop』コマンド

$
0
0

サラリーマン投資家も増えた昨今、仕事中でも株価を確認したい人もいるだろう。
もしそれがアメリカ市場ならば、この『Mop』コマンドを使用することでコンソール上でその株価を調べる事も可能だ。

1.インストール

まずはインストール。
『Mop』はgoで記述されているので、対象マシンにはすでにgo及びgitがインストールされている事が前提となる。

go get github.com/michaeldv/mop
cd $GOPATH/src/github.com/michaeldv/mop
make install

 

完了後、goでインストールしたコマンドを利用出来るようにPATHを通す必要がある。

echo 'export PATH="$PATH:$GOPATH/bin"' >> $HOME/.bashrc
source ~/.bashrc

2.コマンド実行

後は、コマンドを実行するだけだ。

cmd

20150926_000000

株価の他、対円、対ユーロなども確認することが出来るようだ。
銘柄を追加する場合は、「+」キーで銘柄名を入力すると行える。

株解析チャートから自動発注ロボットまで! Excel VBAで極めるシステムトレード 株解析チャートから自動発注ロボットまで! Excel VBAで極めるシステムトレード

dateコマンドで覚えておきたい使い方5個

$
0
0

Linux・UNIXで日時を取得する際に良く使用されるdateコマンド。
今回は、このdateコマンドで覚えておくと便利な使い方についてをまとめてみる事にする。

1.基本的な使い方

説明不要と思われるが、基本的には以下のようにコマンドを実行することで、現在のシステム時間を取得する事が出来る。

date

20150929_000001

[root@test-centos7 ~]# date
2015年  9月 29日 火曜日 05:59:42 JST

 

2.出力フォーマットを指定する

dateコマンドでは、「+」以降に以下のようなフォーマットを組み合わせて指定することで、出力される時刻のフォーマットを指定することが出来る。

%Y 西暦4桁(1970~)
%y 西暦2桁
%C 世紀
%m 月(01~12)
%b ロケール表示での月の省略名 (例: Jan)
%B  ロケール表示での月の完全名 (例: January)
%d
%e スペースで字幅調整された月の中の何日目かを表す値。%_d と同様
%H 時刻(24H)
%k スペース詰めの時 ( 0..23)。 %_H と同様
%I 時刻(AM/PM)
%l スペース詰めの時 ( 1..12)。 %_I と同様
%p AM/PM表記(大文字)
%P AM/PM表記(小文字)
%m
%s
%N ナノ秒
%a ロケール表示による曜日の省略名 (例: Sun、日)
%A ロケール表示での曜日の完全名 (例: Sunday、日曜日)
%z +hhmm 形式でのタイムゾーン (例: -0400)
%:z +hh:mm 形式でのタイムゾーン (例: -04:00)
%::z +hh:mm:ss 形式でのタイムゾーン (例: -04:00:00)
%:::z 必要な精度に応じて : が使用されるタイムゾーン表示 (例: -04, +05:30)
%Z 英字でのタイムゾーン省略形 (例: EDT)
%j 年の開始日からの日数 (001..366)
%s 1970-01-01 00:00:00 UTC からの秒数
%u 週の何日目かを表す値 (1..7); 1 が月曜日
%w 週の何日目かを表す値 (0..6); 0 を日曜日とする
%W 月曜日を週初めとした週番号 (00..53)
%U 日曜日を週初めとした週番号 (00..53)
%V ISO 週番号。月曜日を週初めとする (01..53)
%g ISO 週番号の最後の2桁 (%G 参照)
%G ISO 週番号の年部分 (%V 参照)。通常は %V と同時に使用される
%n 改行
%t 水平タブ
[root@test-centos7 ~]# # 例)YYYYMMDD_HHMMSSを表示させる
[root@test-centos7 ~]# date +%Y%m%d_%H%M%S
20150930_112417

上記フォーマットのように一つ一つを設定する他、最初からある程度まとまったフォーマットを指定する事も出来る。

%c ロケール表示での日付と時刻 (例: Thu Mar  3 23:05:25 2005)
%D 日付。 %m/%d/%y と同様
%F 完全形式の日付。 %Y-%m-%d と同様
%x ロケール表示での日付 (例: 12/31/99)
%r ロケール12時間表示での時刻 (例 11:11:04 PM)
%R 24時間表示での時および分。%H:%M と同様
%T 時刻。%H:%M:%S と同様
%X ロケール表示での時刻 (例: 23:13:48)
%j 年の開始日からの日数 (001..366)
%s 1970-01-01 00:00:00 UTC からの秒数

 

このフォーマット指定を利用して当日作業用ディレクトリの作成や一時ファイル名に使用する等、色々な使い方がある。

3.○時間後、○日前といった日時を取得する

GNU拡張されたdateコマンドの場合、「-d」オプションを使用することで○時間前後、○日前後といった指定する時刻を取得する事が出来る。
かなり柔軟な指定の仕方が出来るので、ここではその一部の例だけを紹介する。

●一日前、後の日付を求める

[root@test-centos7 ~]# # 現在の日時
[root@test-centos7 ~]# date
2015年  9月 30日 水曜日 11:50:48 JST
[root@test-centos7 ~]#
[root@test-centos7 ~]# # 一日前の日時
[root@test-centos7 ~]# date -d '-1day'
2015年  9月 29日 火曜日 11:50:55 JST
[root@test-centos7 ~]#
[root@test-centos7 ~]# # 一日後の日時
[root@test-centos7 ~]# date -d '1day'
2015年 10月  1日 木曜日 11:51:06 JST

●一時間前、一ヶ月後、2年後の日時を求める

[root@test-centos7 ~]# # 現在の日時
[root@test-centos7 ~]# date
2015年  9月 30日 水曜日 11:55:26 JST
[root@test-centos7 ~]#
[root@test-centos7 ~]# # 一時間前の日時
[root@test-centos7 ~]# date -d '-1hour'
2015年  9月 30日 水曜日 10:55:38 JST
[root@test-centos7 ~]#
[root@test-centos7 ~]# # 一ヶ月後の日時
[root@test-centos7 ~]# date -d '1month'
2015年 10月 30日 金曜日 11:55:53 JST
[root@test-centos7 ~]#
[root@test-centos7 ~]# # 2年後の日時
[root@test-centos7 ~]# date -d '1year'
2016年  9月 30日 金曜日 11:57:24 JST

●来月の月初、3ヶ月先の月末日付を求める

[root@test-centos7 ~]# # 現在の日時
[root@test-centos7 ~]# date +%Y/%m/01
2015/09/01
[root@test-centos7 ~]#
[root@test-centos7 ~]# # 来月の月初
[root@test-centos7 ~]# date +%Y/%m/01 -d '+1 month'
2015/10/01
[root@test-centos7 ~]#
[root@test-centos7 ~]# # 3ヶ月後の月末
[root@test-centos7 ~]# date +%Y/%m/%d -d "-1day `date +%Y%m01 -d '+4 month'`"
2015/12/31

4.ファイルの編集日時を取得する

こちらもGNU拡張されたコマンドである必要があるが、「-r」オプションを使用することでファイルの最終更新日を取得することが出来る。

[root@test-centos7 ~]# ls -la /work/test*
-rw-r--r--. 1 root root   36814848  6月 20 19:37 /work/test.image
-rw-r--r--. 1 root root   36814848  7月 26 11:28 /work/test.image.bk
-rw-r--r--. 1 root root        237  9月  6 15:44 /work/test.log
-rw-r--r--. 1 root root        108  7月  7 20:09 /work/test.txt
-rw-r--r--. 1 root root        108  7月 26 11:28 /work/test.txt.bk
-rw-r--r--. 1 root root 1024000000  7月 11 05:12 /work/test1
-rw-r--r--. 1 root root 1024000000  7月 26 11:29 /work/test1.bk
-rw-r--r--. 1 root root         33  9月 11 07:00 /work/test123
-rw-r--r--. 1 root root 1024000000  7月 11 05:13 /work/test2
-rw-r--r--. 1 root root 1024000000  7月 26 11:29 /work/test2.bk
-rw-r--r--. 1 root root        297  9月  6 16:07 /work/test2.log
-rw-r--r--. 1 root root        230  6月  4 07:17 /work/test2.txt
-rw-r--r--. 1 root root        230  7月 26 11:28 /work/test2.txt.bk
-rw-r--r--. 1 root root        298  9月  6 16:21 /work/test3.log
-rw-r--r--. 1 root root        142  9月  8 06:30 /work/test4.sh
-rw-r--r--. 1 root root        102  9月 23 07:56 /work/test5.txt
-rw-r--r--. 1 root root        215  9月 24 06:00 /work/test5_.txt
-rw-r--r--. 1 root root        102  9月 23 07:57 /work/test5_1.txt
-rw-r--r--. 1 root root         56  9月 23 08:13 /work/test5_2.txt
-rw-r--r--. 1 root root        144  9月 23 12:40 /work/test5_3.txt
-rw-r--r--. 1 root root        102  9月 23 13:25 /work/test5_4.txt
-rw-r--r--. 1 root root         54  9月 23 13:30 /work/test5_5.txt
-rw-r--r--. 1 root root        129  9月 24 06:03 /work/test5_6.txt
-rw-r--r--. 1 root root        102  9月 25 06:07 /work/test5_7.txt
[root@test-centos7 ~]# date -r /work/test.log
2015年  9月  6日 日曜日 15:44:26 JST

5.日時を設定する

「-s」オプションを使用することで、システム日時を変更することが出来る。

20150930_000000

[root@test-centos7 ~]# date
2015年  9月 30日 水曜日 14:15:01 JST
[root@test-centos7 ~]# date -s "2015/01/01 11:00:00"
2015年  1月  1日 木曜日 11:00:00 JST
[root@test-centos7 ~]#
[root@test-centos7 ~]# date
2015年  1月  1日 木曜日 11:00:03 JST
Docker実践入門――Linuxコンテナ技術の基礎から応用まで (Software Design plus) Docker実践入門――Linuxコンテナ技術の基礎から応用まで (Software Design plus)

nkfコマンド・iconvコマンドで覚えておきたい文字コード・改行コード変換方法いろいろ

$
0
0

Linuxで日本語を含むファイルやWindowsで作成したファイルを利用する際にネックになる、文字コードや改行コード。
今回は、それらの変換で良く利用されるコマンド、nkfコマンドとiconvコマンドで覚えておくと便利な使い方についてをまとめてみる事にする。

個人的な感想としては、nkfコマンドの方が多機能なのだが、iconvコマンドの方が新しくとっつきやすい、デフォルトで用意されている事が多い印象がある。

1.文字コードの変換を行う

まずは基本の機能。文字コードを変換する場合は、以下のようにコマンドを実行する。

1-1.nfkの場合

nkfコマンドの場合は、以下のオプションを駆使して文字コード変換を行う。

ファイルの文字コードを指定する J … JIS
E … EUC-JP
S … SJIS
W … UTF-8
変換後の文字コードを指定する j … JIS
e … EUC-JP
s … SJIS
w … UTF-8

 

例えば、EUC-JPのファイルをUTF-8に変換する場合は、以下のようにコマンドを実行すれば良い。

nkf -Ew 対象ファイル

20150930_000001

[root@test-centos7 ~]# file /work/nkftest1.txt
/work/nkftest1.txt: ISO-8859 text
[root@test-centos7 ~]# cat /work/nkftest1.txt
、「、「、「、「、「、「

[root@test-centos7 ~]# nkf -Ew /work/nkftest1.txt
ああああああ

1-2.iconvの場合

iconvの場合は、以下のようにコマンドを実行することで文字コード変換を行う事が出来る。

iconv -f ファイルの文字コード -t 変換させる文字コード 対象ファイル

20151001_000000

[root@test-centos7 ~]# file /work/nkftest1.txt
/work/nkftest1.txt: ISO-8859 text
[root@test-centos7 ~]#
[root@test-centos7 ~]# iconv -f eucjp -t utf-8 /work/nkftest1.txt
ああああああ

2.改行コードの変換を行う

nkfコマンドで改行コードを変換する場合は、以下のオプションを使用して変換を行う。

-Lu unix改行形式(LF)に変換
-Lw windows改行形式(CRLF)に変換
-Lm macintosh改行形式(CR)に変換

 

なお、改行コードの変換はnkfでは可能だが、iconvでは対応していない。
nkfが入っていない場合は、別途「dos2unix」「unix2dos」コマンドで対応すると良いだろう。

3.ファイルの文字コードを確認する

ファイルの文字コードを確認する場合も、nkfコマンドで「-g」オプションを使用することで実施可能だ。
なお、nkfコマンドがない場合は「file」コマンドを使用することで文字コードを確認することが出来る。

nkf -g 対象ファイル

20151001_000001

[root@test-centos7 ~]# nkf -g /work/nkftest1.txt
EUC-JP
[root@test-centos7 ~]# nkf -g /work/nkftest2.txt
Shift_JIS
[root@test-centos7 ~]#
[root@test-centos7 ~]# file /work/nkftest1.txt
/work/nkftest1.txt: ISO-8859 text
[root@test-centos7 ~]# file /work/nkftest2.txt
/work/nkftest2.txt: Non-ISO extended-ASCII text

4.文字コード・改行コードを変換して上書き保存する

文字コード・改行コードを変換した状態で上書き保存する場合は、nkfコマンドで「–overwrite」オプションを付与すると良いだろう。

nkf -変換オプション --overwrite 対象ファイル

20151001_000002

[root@test-centos7 ~]# nkf -g /work/nkftest1.txt
EUC-JP
[root@test-centos7 ~]# nkf -s --overwrite /work/nkftest1.txt
[root@test-centos7 ~]# nkf -g /work/nkftest1.txt
Shift_JIS

以上、タイトルだとnkfとiconvと記述したが、ほとんどnkfコマンドだけだった。
最近だとnkf入ってない事も多いので、まぁ環境に合わせて使い分けて貰えれば…

文字コード「超」研究 改訂第2版 文字コード「超」研究 改訂第2版

シェルスクリプトで出力結果の桁数合わせ、スペースでの幅合わせを行う

$
0
0

先日、シェルスクリプトで出力結果をキレイに整形する必要があり、その際に出力結果の桁数合わせ、幅合わせを行う必要があったのでその備忘。
どちらも、pfintfコマンドで実現出来る。

1.桁あわせを行う場合

桁あわせを行う場合、以下のように記述する。

printf &quot;%0桁数d\n&quot; 数字

 

例えば、34という数字を5桁で出力させる場合は以下のようにする。

printf &quot;%05d\n&quot; 34

20151013_000000

[root@test-centos7 ~]# printf "%05d\n" 34
00034

2.スペースで幅合わせを行う場合

スペースでの幅合わせを行う場合、以下のように記述する。

printf &quot;%幅数s\n&quot; 表示文字

 

例えば、56という数字を10文字分のスペースで出力させる場合は以下のようにする。

printf &quot;%10s\n&quot; 56

20151013_000001

[root@test-centos7 ~]# printf "%10s\n" 56
        56

 

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

Pythonによるssh自動接続用スクリプト(試作)

$
0
0

(すっごい久々にブログの記事書いた気がする…)

この度、転職が決まったんですが新しい職場だとクライアントはMacを使える事になった。
今までの職場だとTeratermのlistboxを使用したマクロでサーバにログインしてたので、似たようなものをMac用に作ることにしてみた。

で、最初bashで書こうかと思ったんだけど、勉強がてらPythonで書いてみようと思いPythonにした。
とりあえず、今の状態で出来ることとしては以下。

  • host.listを元に接続先を選択してログイン
  • suでユーザのスイッチ可
  • 操作ログの自動取得(ログ中にタイムスタンプの挿入不可)

なお、sshでの接続にはpexpectを用いているので、それだけは別途インストールが必要になる。
ログイン時に実行させる任意のコマンドをファイルに書いといたり、操作ログに操作時のタイムスタンプを挿入させたりしたいけど、まだ出来てない…どうもpexpectなどで直接ログ取得時にタイムスタンプを付与すると、コマンドの実行結果行に中途半端なタイムスタンプがついちゃったり、入力文字列の1つ1つにタイムスタンプがついて大変うざったい事になるので、scriptコマンドの時と同様に別プロセスで付与させるしかないのかな?

今のトコ、必要になるファイルはスクリプトファイル本体とhost.list(接続先ホストの情報を記述している)の2ファイルのみ。
あんまりセキュリティは考えていない…(今後の事考えるとよろしくないかも)。

1.host.list

基本的に、今までのTeratermマクロのものを使いまわせるよう、同じフォーマットとしている。

●host.list

# SSHAutoLogin.ttl用 ログインホスト設定ファイル
# 左から順に、以下の内容を記述していく。
# HOST_NAME(任意の名称。接続するホストの選択時やログ名に利用する。必須。)
# HOST_IP(ホストのIPアドレス。接続時に利用する。必須。)
# HOST_ROOT_USER(管理者ユーザ名。ログインユーザを設定してスイッチする場合はrootユーザを設定。必須。)
# HOST_ROOT_PASS(管理者ユーザパスワード。必須。)
# HOST_USER(ログインユーザ名。管理者ユーザで直接ログイン出来る場合は不要。)
# HOST_PASS(ログインユーザパスワード。管理者ユーザで直接ログイン出来る場合は不要。)
# SUDO_FLAG(スイッチ文を「sudo su -」とするか否か。何かしら(0でも1でも)入力すると有効になる。スイッチ時のコマンドが「su -」の場合は不要)

# HOST_NAME, HOST_IP, HOST_ROOT_USER, HOST_ROOT_PASS, HOST_USER, HOST_PASS, SUDO_FLAG

# CentOS(「su -」)でスイッチする例
Test-CentOS1,172.28.0.101,root,password,test,password

# CentOS(「su -」)でスイッチせずに直接ログインする例
Test-CentOS2,172.28.0.102,root,password

# Ubuntu(sudo su -)でスイッチする例
Test-Ubuntu1,172.28.0.103,test,password,test,password,1

 

本当は、Macで使うこと前提ならssh接続時に背景画像を変える事を前提に、その辺の設定を記述しても良さそうだけど、今はいいや…

2.ssh_connect.py

スクリプト本体。
あまりいい出来ではない…少しづつ直していこう。

●ssh_connect.py

#! /usr/bin/python
# -*- coding: utf-8 -*-

##################
# モジュール読込 #
##################
from __future__ import division
import curses
from math import *
import pexpect
import locale
locale.setlocale(locale.LC_ALL, "")
from datetime import datetime
import logging

########
# 関数 #
########

def ssh_connect(line_no):
    # 接続時に使用する情報を取得
    connect_host_name      = "".join(map(str,host_name_list[line_no]))
    connect_host_ip        = "".join(map(str,host_ip_list[line_no]))
    connect_host_root_user = "".join(map(str,host_root_user_list[line_no]))
    connect_host_root_pass = "".join(map(str,host_root_pass_list[line_no]))
    connect_host_user      = "".join(map(str,host_user_list[line_no]))
    connect_host_pass      = "".join(map(str,host_pass_list[line_no]))
    connect_sudo_flag      = "".join(map(str,sudo_flag_list[line_no]))

    # ログインユーザーの指定有無を確認
    if connect_host_user == "":
        connect_user = connect_host_root_user
        connect_pass = connect_host_root_pass
    else:
        connect_user = connect_host_user
        connect_pass = connect_host_pass

    foo = pexpect.spawn('ssh -o "StrictHostKeyChecking=no" %s@%s' % (connect_user, connect_host_ip))
    foo.logfile_read = open('%s%s.log.%s' % ( log_dir,connect_host_name,now_time ),"w")
    foo.expect(['.*ssword:','パスワード:'])
    print foo.before.rstrip()
    print foo.after.rstrip()
    foo.sendline(connect_pass)
    if not connect_host_user == "":
        foo.expect(['$','#'])
        print foo.before.strip()
        print foo.after.strip()
        foo.sendline('su - %s' % (connect_host_root_user))

        foo.expect(['.*ssword:','パスワード:'])
        print foo.before.strip()
        print foo.after.strip()
        foo.sendline(connect_host_root_pass)
    foo.interact()

############
# 設定関連 #
############
max_row      = 20
list_file    = '/tmp/data.csv'
command_file = ''
log_dir      = '/tmp/'
now_time     = datetime.now().strftime('%Y%m%d_%H%M%S')

##################
# curses関連設定 #
##################
# リスト表示件数
screen        = curses.initscr()
curses.noecho()
curses.cbreak()
curses.start_color()
screen.keypad( 1 )
curses.init_pair(1,curses.COLOR_BLACK, curses.COLOR_CYAN)
highlightText = curses.color_pair( 1 )
normalText    = curses.A_NORMAL
screen.border( 0 )
curses.curs_set( 0 )
box           = curses.newwin( max_row + 2, 100, 1, 1 )
box.box()

##################
# リスト情報取得 #
##################
f = open(list_file)
line = f.readline()
i = 0
host_name_list      = []
host_ip_list        = []
host_root_user_list = []
host_root_pass_list = []
host_user_list      = []
host_pass_list      = []
sudo_flag_list      = []
while line:
    line = line.strip()
    # コメント・空行を除外
    if line.startswith( "#" ) or len( line ) == 0:
        line = f.readline()
        continue
    # リストの各要素を取得
    line_column = len( line.split(',') )
    if line_column == 4:
        host_name      = line.split(',')[0]
        host_ip        = line.split(',')[1]
        host_root_user = line.split(',')[2]
        host_root_pass = line.split(',')[3]
        host_user      = ""
        host_pass      = ""
        sudo_flag      = ""
    elif line_column == 6:
        host_name      = line.split(',')[0]
        host_ip        = line.split(',')[1]
        host_root_user = line.split(',')[2]
        host_root_pass = line.split(',')[3]
        host_user      = line.split(',')[4]
        host_pass      = line.split(',')[5]
        sudo_flag      = ""
    elif line_column == 7:
        host_name      = line.split(',')[0]
        host_ip        = line.split(',')[1]
        host_root_user = line.split(',')[2]
        host_root_pass = line.split(',')[3]
        host_user      = line.split(',')[4]
        host_pass      = line.split(',')[5]
        sudo_flag      = line.split(',')[6]
    else:
        exit(1)
        print "リストに誤りがあります。"
        print line
    host_name_list      += [[host_name]]
    host_ip_list        += [[host_ip]]
    host_root_user_list += [[host_root_user]]
    host_root_pass_list += [[host_root_pass]]
    host_user_list      += [[host_user]]
    host_pass_list      += [[host_pass]]
    sudo_flag_list      += [[sudo_flag]]
    line = f.readline()
f.close
row_num = len( host_name_list )

##############
# リスト表示 #
##############
pages = int( ceil( row_num / max_row ) )
position = 1
page = 1
for i in range( 1, max_row + 1 ):
    if row_num == 0:
        box.addstr( 1, 1, "There aren't host_name_list", highlightText )
    else:
        if (i == position):
            box.addstr( i, 2, str( i ) + " - " + "".join(map(str,host_name_list[ i - 1 ])), highlightText )
        else:
            box.addstr( i, 2, str( i ) + " - " + "".join(map(str,host_name_list[ i - 1 ])), normalText )
        if i == row_num:
            break
screen.refresh()
box.refresh()

##########################
# ホスト選択画面キー操作 #
##########################
x = screen.getch()
while x != 27:

    # 下キー押下時の動作
    if x == curses.KEY_DOWN:
        if page == 1:
            if position < i:
                 position = position + 1
             else:
                 if pages > 1:
                    page = page + 1
                    position = 1 + ( max_row * ( page - 1 ) )
        elif page == pages:
            if position < row_num:
                position = position + 1
        else:
            if position < max_row + ( max_row * ( page - 1 ) ):
                 position = position + 1
             else:
                 page = page + 1
                 position = 1 + ( max_row * ( page - 1 ) )
     # 上キー押下時の動作
     if x == curses.KEY_UP:
         if page == 1:
             if position > 1:
                position = position - 1
        else:
            if position > ( 1 + ( max_row * ( page - 1 ) ) ):
                position = position - 1
            else:
                page = page - 1
                position = max_row + ( max_row * ( page - 1 ) )

    # 左キー押下時の動作
    if x == curses.KEY_LEFT:
        if page > 1:
            page = page - 1
            position = 1 + ( max_row * ( page - 1 ) )

    # 右キー押下時の動作
    if x == curses.KEY_RIGHT:
        if page < pages:
            page = page + 1
            position = ( 1 + ( max_row * ( page - 1 ) ) )

    # Enter押下時(決定)の処理
    if x == ord( "\n" ) and row_num != 0:
        screen.erase()
        screen.border( 0 )

        curses.endwin()
        ssh_connect(position - 1)
        exit()

    box.erase()
    screen.border( 0 )
    box.border( 0 )

    for i in range( 1 + ( max_row * ( page - 1 ) ), max_row + 1 + ( max_row * ( page - 1 ) ) ):
        if row_num == 0:
            box.addstr( 1, 1, "There aren't host_name_list",  highlightText )
        else:
            if ( i + ( max_row * ( page - 1 ) ) == position + ( max_row * ( page - 1 ) ) ):
                box.addstr( i - ( max_row * ( page - 1 ) ), 2, str( i ) + " - " + "".join(map(str,host_name_list[ i - 1 ])), highlightText )
            else:
                box.addstr( i - ( max_row * ( page - 1 ) ), 2, str( i ) + " - " + "".join(map(str,host_name_list[ i - 1 ])), normalText )
            if i == row_num:
                break

    screen.refresh()
    box.refresh()
    x = screen.getch()

curses.endwin()
exit()

 

実際に使用した際のイメージがこちら
コマンドを実行すると…

スクリーンショット 2015-11-06 22.30.16

 

接続先のリストが表示されるので、接続するホストを矢印キーで選択しEnter。

スクリーンショット 2015-11-06 22.30.29

 

ログイン完了。
rootにスイッチする場合は、host.listで指定してればスイッチするようにしている。

スクリーンショット 2015-11-06 22.30.40

 

まぁ、これからある程度使っていくだろうし、少しづつブラッシュアップしていこう。

サイバーセキュリティプログラミング ―Pythonで学ぶハッカーの思考 サイバーセキュリティプログラミング ―Pythonで学ぶハッカーの思考

Pythonによるssh自動接続用スクリプト(試作) 鍵認証ログイン対応

$
0
0

先日作成したssh自動接続用のスクリプト、基本的にパスワード認証のみで考えていたのだけどAWSとかAzureだと鍵認証なんだよね。
という訳で、微修正ながら鍵認証に対応させてみた。

1.host.list

host.listには、鍵ファイルの指定列を新しく追加した。

●host.list

# SSHAutoLogin.ttl用 ログインホスト設定ファイル
# 左から順に、以下の内容を記述していく。
# HOST_NAME(任意の名称。接続するホストの選択時やログ名に利用する。必須。)
# HOST_IP(ホストのIPアドレス。接続時に利用する。必須。)
# KEY_FILE(鍵ファイルの設置PATH。ない場合は空欄で記述。)
# HOST_ROOT_USER(管理者ユーザ名。ログインユーザを設定してスイッチする場合はrootユーザを設定。必須。)
# HOST_ROOT_PASS(管理者ユーザパスワード。必須。)
# HOST_USER(ログインユーザ名。管理者ユーザで直接ログイン出来る場合は不要。)
# HOST_PASS(ログインユーザパスワード。管理者ユーザで直接ログイン出来る場合は不要。)
# SUDO_FLAG(スイッチ文を「sudo su -」とするか否か。何かしら(0でも1でも)入力すると有効になる。スイッチ時のコマンドが「su -」の場合は不要)

# HOST_NAME, HOST_IP, HOST_ROOT_USER, HOST_ROOT_PASS, HOST_USER, HOST_PASS, SUDO_FLAG

# CentOS(「su -」)でスイッチする例
Test-CentOS1,172.28.0.101,,root,password,test,password

# CentOS(「su -」)でスイッチせずに直接ログインする例
Test-CentOS2,172.28.0.102,,root,password

# Ubuntu(sudo su -)でスイッチする例
Test-Ubuntu1,172.28.0.103,,test,password,test,password,1

# AWSテスト
AWSテスト,XXX.XXX.XXX.XXX,/tmp/test.pem,centos,

2.ssh_connect.py

スクリプト本体。
まぁ、ちょっとだけ微修正しただけだけど…

●ssh_connect.py

#! /usr/bin/python
# -*- coding: utf-8 -*-
# +-------------------------------------------+
# +                                           +
# +                                           +
# +-------------------------------------------+

##################
# モジュール読込 #
##################
from __future__ import division
import curses
from math import *
import pexpect
import locale
locale.setlocale(locale.LC_ALL, "")
from datetime import datetime
import logging

########
# 関数 #
########

def ssh_connect(line_no):
    # 接続時に使用する情報を取得
    connect_host_name      = "".join(map(str,host_name_list[line_no]))
    connect_host_ip        = "".join(map(str,host_ip_list[line_no]))
    connect_key_file       = "".join(map(str,key_file_list[line_no]))
    connect_host_root_user = "".join(map(str,host_root_user_list[line_no]))
    connect_host_root_pass = "".join(map(str,host_root_pass_list[line_no]))
    connect_host_user      = "".join(map(str,host_user_list[line_no]))
    connect_host_pass      = "".join(map(str,host_pass_list[line_no]))
    connect_sudo_flag      = "".join(map(str,sudo_flag_list[line_no]))

    # ログインユーザーの指定有無を確認
    if connect_host_user == "":
        connect_user = connect_host_root_user
        connect_pass = connect_host_root_pass
    else:
        connect_user = connect_host_user
        connect_pass = connect_host_pass

    if connect_key_file == "":
        foo = pexpect.spawn('ssh -o "StrictHostKeyChecking=no" %s@%s' % (connect_user, connect_host_ip))
    else:
        foo = pexpect.spawn('ssh -o "StrictHostKeyChecking=no" -i %s %s@%s' % (connect_key_file, connect_user, connect_host_ip))

    foo.logfile_read = open('%s%s.log.%s' % ( log_dir,connect_host_name,now_time ),"w")
    if not connect_pass == "":
        foo.expect(['.*ssword:','パスワード:'])
        print foo.before.rstrip()
        print foo.after.rstrip()
        foo.sendline(connect_pass)
    if not connect_host_user == "":
        foo.expect(['$','#'])
        print foo.before.strip()
        print foo.after.strip()
        foo.sendline('su - %s' % (connect_host_root_user))

        foo.expect(['.*ssword:','パスワード:'])
        print foo.before.strip()
        print foo.after.strip()
        foo.sendline(connect_host_root_pass)
    foo.interact()


############
# 設定関連 #
############
max_row      = 20
list_file    = '/tmp/data.csv'
command_file = ''
log_dir      = '/tmp/'
now_time     = datetime.now().strftime('%Y%m%d_%H%M%S')

##################
# curses関連設定 #
##################
# リスト表示件数
screen        = curses.initscr()
curses.noecho()
curses.cbreak()
curses.start_color()
screen.keypad( 1 )
curses.init_pair(1,curses.COLOR_BLACK, curses.COLOR_CYAN)
highlightText = curses.color_pair( 1 )
normalText    = curses.A_NORMAL
screen.border( 0 )
curses.curs_set( 0 )
box           = curses.newwin( max_row + 2, 100, 1, 1 )
box.box()


##################
# リスト情報取得 #
##################
f = open(list_file)
line = f.readline()
i = 0
host_name_list      = []
host_ip_list        = []
key_file_list       = []
host_root_user_list = []
host_root_pass_list = []
host_user_list      = []
host_pass_list      = []
sudo_flag_list      = []
while line:
    line = line.strip()
    # コメント・空行を除外
    if line.startswith( "#" ) or len( line ) == 0:
        line = f.readline()
        continue
    # リストの各要素を取得
    line_column = len( line.split(',') )
    if line_column == 5:
        host_name      = line.split(',')[0]
        host_ip        = line.split(',')[1]
        key_file       = line.split(',')[2]
        host_root_user = line.split(',')[3]
        host_root_pass = line.split(',')[4]
        host_user      = ""
        host_pass      = ""
        sudo_flag      = ""
    elif line_column == 7:
        host_name      = line.split(',')[0]
        host_ip        = line.split(',')[1]
        key_file       = line.split(',')[2]
        host_root_user = line.split(',')[3]
        host_root_pass = line.split(',')[4]
        host_user      = line.split(',')[5]
        host_pass      = line.split(',')[6]
        sudo_flag      = ""
    elif line_column == 8:
        host_name      = line.split(',')[0]
        host_ip        = line.split(',')[1]
        key_file       = line.split(',')[2]
        host_root_user = line.split(',')[3]
        host_root_pass = line.split(',')[4]
        host_user      = line.split(',')[5]
        host_pass      = line.split(',')[6]
        sudo_flag      = line.split(',')[7]
    else:
        curses.endwin()
        print "リストに誤りがあります。"
        print line
        exit(1)
    host_name_list      += [[host_name]]
    host_ip_list        += [[host_ip]]
    key_file_list       += [[key_file]]
    host_root_user_list += [[host_root_user]]
    host_root_pass_list += [[host_root_pass]]
    host_user_list      += [[host_user]]
    host_pass_list      += [[host_pass]]
    sudo_flag_list      += [[sudo_flag]]
    line = f.readline()
f.close
row_num = len( host_name_list )


##############
# リスト表示 #
##############
pages = int( ceil( row_num / max_row ) )
position = 1
page = 1
for i in range( 1, max_row + 1 ):
    if row_num == 0:
        box.addstr( 1, 1, "There aren't host_name_list", highlightText )
    else:
        if (i == position):
            box.addstr( i, 2, str( i ) + " - " + "".join(map(str,host_name_list[ i - 1 ])), highlightText )
        else:
            box.addstr( i, 2, str( i ) + " - " + "".join(map(str,host_name_list[ i - 1 ])), normalText )
        if i == row_num:
            break
screen.refresh()
box.refresh()


##########################
# ホスト選択画面キー操作 #
##########################
x = screen.getch()
while x != 27:

    # 下キー押下時の動作
    if x == curses.KEY_DOWN:
        if page == 1:
            if position < i:
                 position = position + 1
             else:
                 if pages > 1:
                    page = page + 1
                    position = 1 + ( max_row * ( page - 1 ) )
        elif page == pages:
            if position < row_num:
                position = position + 1
        else:
            if position < max_row + ( max_row * ( page - 1 ) ):
                 position = position + 1
             else:
                 page = page + 1
                 position = 1 + ( max_row * ( page - 1 ) )
     # 上キー押下時の動作
     if x == curses.KEY_UP:
         if page == 1:
             if position > 1:
                position = position - 1
        else:
            if position > ( 1 + ( max_row * ( page - 1 ) ) ):
                position = position - 1
            else:
                page = page - 1
                position = max_row + ( max_row * ( page - 1 ) )

    # 左キー押下時の動作
    if x == curses.KEY_LEFT:
        if page > 1:
            page = page - 1
            position = 1 + ( max_row * ( page - 1 ) )

    # 右キー押下時の動作
    if x == curses.KEY_RIGHT:
        if page < pages:
            page = page + 1
            position = ( 1 + ( max_row * ( page - 1 ) ) )

    # Enter押下時(決定)の処理
    if x == ord( "\n" ) and row_num != 0:
        screen.erase()
        screen.border( 0 )

        curses.endwin()
        ssh_connect(position - 1)
        exit()

    box.erase()
    screen.border( 0 )
    box.border( 0 )

    for i in range( 1 + ( max_row * ( page - 1 ) ), max_row + 1 + ( max_row * ( page - 1 ) ) ):
        if row_num == 0:
            box.addstr( 1, 1, "There aren't host_name_list",  highlightText )
        else:
            if ( i + ( max_row * ( page - 1 ) ) == position + ( max_row * ( page - 1 ) ) ):
                box.addstr( i - ( max_row * ( page - 1 ) ), 2, str( i ) + " - " + "".join(map(str,host_name_list[ i - 1 ])), highlightText )
            else:
                box.addstr( i - ( max_row * ( page - 1 ) ), 2, str( i ) + " - " + "".join(map(str,host_name_list[ i - 1 ])), normalText )
            if i == row_num:
                break

    screen.refresh()
    box.refresh()
    x = screen.getch()

curses.endwin()
exit()
プログラミング超初心者が初心者になるためのPython入門(1) セットアップ・文字列・数値編 プログラミング超初心者が初心者になるためのPython入門(1) セットアップ・文字列・数値編

ログイン先を選択して自動ログインを行うTeratermマクロ(鍵認証対応版)

$
0
0

先日作成したPythonスクリプトで鍵認証対応させたので、Teratermマクロでもやってみる。

1.SSHAutoLogin.ttl

変更点としては、こちらの内容に鍵認証を加えただけだ。

;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;  Filename : SSHAutoLogin.ttl
;  Description : SSH Auto login - host selection listbox from host.list
;  Author : Blacknon
;  Created : 2015/01/18
;  Modified : 2015/11/10
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
;;-------------------------------------------------------
;; 接続時の基本的な情報を設定する
;;-------------------------------------------------------
;; ホストに関する情報をもつファイル「host.list」の場所を設定する
 HOST_FILE = "host.list"
 
;; ログイン時に実行させるコマンドの情報をもつファイル「command.list」の場所を設定する
 COMMAND_FILE = "command.list"
 
;; ログ作成用ディレクトリの情報を取得する
 Getdir CurrentDir
 LOG_DIR_PATH = CurrentDir
 Strconcat LOG_DIR_PATH '\log\'
 
;;-------------------------------------------------------
;; ホスト選択画面を作成する
;;-------------------------------------------------------
;; ホストファイルの行数を取得する
 Fileopen HOST_LIST HOST_FILE 0
 i = 0
 While
     Filereadln HOST_LIST LIST_LINE
 
    ;;ファイル読み込みの終了処理
     If result = 1 Break
 
    ;; 空白行を無視する
     Strlen LIST_LINE
     If result = 0 continue
 
    ;; 「#」から始まる行をコメントとして無視
     Strmatch LIST_LINE '^#'
     If result &amp;lt;&amp;gt; 0 continue
 
     i=i+1
 EndWhile
 
;; 配列を作成
 Strdim HOST_NAME i
 Strdim HOST_IP i
 Strdim KEY_FILE i
 Strdim HOST_USER i
 Strdim HOST_PASS i
 Strdim HOST_ROOT_USER i
 Strdim HOST_ROOT_PASS i
 Strdim HOST_SUDO_FLAG i
 
;; ホストに関する情報をホストファイルから取得する
 Fileopen HOST_LIST HOST_FILE 0
 i = 0
 While
     Filereadln HOST_LIST LIST_LINE
 
    ;;ファイル読み込みの終了処理
     If result = 1 Break
 
    ;; 空白行を無視する
     Strlen LIST_LINE
     If result = 0 continue
 
    ;; 「#」から始まる行をコメントとして無視
     Strmatch LIST_LINE '^#'
     If result &amp;lt;&amp;gt; 0 continue
 
    ;;ホストに関する情報を各変数へ代入する
     Strsplit LIST_LINE ','
     HOST_NAME[i]      = Groupmatchstr1
     HOST_IP[i]        = Groupmatchstr2
     KEY_FILE[i]       = Groupmatchstr3
     HOST_ROOT_USER[i] = Groupmatchstr4
     HOST_ROOT_PASS[i] = Groupmatchstr5
     HOST_USER[i]      = Groupmatchstr6
     HOST_PASS[i]      = Groupmatchstr7
     HOST_SUDO_FLAG[i] = Groupmatchstr8
 
     i=i+1
 Endwhile
 
;; ホスト選択画面を表示させる
 listbox 'ログインするホストを選択してください' 'ホスト選択' HOST_NAME
 
;;-------------------------------------------------------
;; 選択されたホストにログインを行う
;;-------------------------------------------------------
;; ホスト選択画面で選択されたホストの情報を変数に代入する
 If result &amp;gt;= 0 then
     HOST_CONNECT_NAME      = HOST_NAME[result]
     HOST_CONNECT_IP        = HOST_IP[result]
     HOST_CONNECT_KEY_FILE  = KEY_FILE[result]
     HOST_CONNECT_ROOT_USER = HOST_ROOT_USER[result]
     HOST_CONNECT_ROOT_PASS = HOST_ROOT_PASS[result]
     HOST_CONNECT_USER      = HOST_USER[result]
     HOST_CONNECT_PASS      = HOST_PASS[result]
     HOST_CONNECT_SUDO_FLAG = HOST_SUDO_FLAG[result]
 Else
     End
 Endif
 
;; ログイン用のユーザーが定義されているか確認する
 Strlen HOST_CONNECT_USER
 If result &amp;lt;&amp;gt; 0 Then
     SSH_CONNECT_USER        = HOST_CONNECT_USER
     SSH_CONNECT_PASS        = HOST_CONNECT_PASS
 Else
     SSH_CONNECT_USER        = HOST_CONNECT_ROOT_USER
     SSH_CONNECT_PASS        = HOST_CONNECT_ROOT_PASS
 Endif
 
;; SSH接続コマンドを作成する
 COMMAND = HOST_CONNECT_IP
 Strconcat COMMAND ':22 /ssh /2 /user='
 Strconcat COMMAND SSH_CONNECT_USER
 
 Strlen SSH_CONNECT_PASS
 If result &amp;lt;&amp;gt; 0 Then
     Strconcat COMMAND ' /passwd='
     Strconcat COMMAND SSH_CONNECT_PASS
 Endif
 
 Strlen HOST_CONNECT_KEY_FILE
 If result &amp;lt;&amp;gt; 0 Then
     Strconcat COMMAND ' /auth=publickey'
     Strconcat COMMAND ' /keyfile='
     Strconcat COMMAND HOST_CONNECT_KEY_FILE
 Else
     Strconcat COMMAND ' /auth=password'
 Endif
 
 
;; SSH接続を行う
 Connect COMMAND
 
;;-------------------------------------------------------
;; ログの記録を開始する
;;-------------------------------------------------------
;; ログ名に利用する日付情報を取得する
 Getdate Str_Getdate
 Strcopy Str_Getdate 1 4 Str_Year
 Strcopy Str_Getdate 6 2 Str_Mon
 Strcopy Str_Getdate 9 2 Str_Day
 
;; ログ名に利用する時刻情報を取得する
 Gettime Str_Gettime
 Strcopy Str_Gettime 1 2 Str_Hour
 Strcopy Str_Gettime 4 2 Str_Min
 Strcopy Str_Gettime 7 2 Str_Sec
 
;; ログ名を生成する
 LOG_PATH = LOG_DIR_PATH
 Strconcat LOG_PATH Str_Year
 Strconcat LOG_PATH Str_Mon
 Strconcat LOG_PATH Str_Day
 Strconcat LOG_PATH '_'
 Strconcat LOG_PATH Str_Hour
 Strconcat LOG_PATH Str_Min
 Strconcat LOG_PATH Str_Sec
 Strconcat LOG_PATH '_'
 Strconcat LOG_PATH HOST_CONNECT_NAME
 Strconcat LOG_PATH '.log'
 
;; 現在記録しているログの情報を取得する
 Loginfo NOW_LOG_PATH
 
;; 現在ログが記録されていた場合、マクロで規定したフォルダに移動する
 If result &amp;lt;&amp;gt; -1 Then
     ;; 一度ログの記録を停止する
      Logclose
 
     ;; 取得されていたログをマクロで規定した場所にコピーする
      Filecopy NOW_LOG_PATH LOG_PATH
 
     ;; 取得されていたログを削除する
      Filedelete NOW_LOG_PATH
 Endif
 
;; ログの記録を開始する
 Logopen LOG_PATH 0 1 1 1
 
;;-------------------------------------------------------
;; Command.listの内容を実行させる
;;-------------------------------------------------------
;; host.listでログインユーザの設定がされていたか確認する
 Strlen HOST_CONNECT_USER
 If result &amp;lt;&amp;gt; 0 Then
      Wait '$' '#'
      Sendln ''
 
      Wait '$' '#'
      Sendln '#rootユーザーにスイッチする'
 
     ;; 「sudo su -」でスイッチする必要がある場合
      Strlen HOST_CONNECT_SUDO_FLAG
      If Result &amp;gt; 0 Then
          Wait '$' '#'
          Sendln 'sudo su -'
 
          Wait ':'
          Sendln SSH_CONNECT_PASS
      Else
          Wait '$' '#'
          Sendln 'su -'
 
          Wait ':'
          Sendln HOST_CONNECT_ROOT_PASS
      Endif
 Endif
 Wait '$' '#'
 Sendln ''
 
;; Command.listを読み込む
 Fileopen COMMAND_LIST COMMAND_FILE 0
 While 1
      Filereadln COMMAND_LIST COMMAND_LIST_LINE
      If RESULT = 1 Break
 
      Flushrecv
      Wait '$' '#'
      Sendln COMMAND_LIST_LINE
 Endwhile
 Fileclose COMMAND_LIST
End

2.host.list

host.listについては、Pythonスクリプトと同じものを使用するので割愛。
command.listについても改修前のものをそのまま使用する。

たった2日でわかるLinuxサーバーCentOS7.0対応 たった2日でわかるLinuxサーバーCentOS7.0対応

cp/mvコマンドで、配置先に同名のファイルがあった場合のみリネームして配置させる

$
0
0

Windowsのエクスプローラーでコピーをすると、同名のファイルがあった場合には以下のような画面が表示される。
その時に表示される選択肢である「コピーするが両方のファイルを保持する」とほぼ同等の動作をLinuxのcp/mvコマンドで実現する場合、どうすればいいのだろう?

20151112_000000

 

厳密な動作は少々異なるが、これらをcp/mvコマンドで実現する場合は「–backup」オプションを付与し、その際の動作を指定する事で実現可能だ。
例えば、連番の場合は以下のようにする。

cp --backup=t コピー元 コピー先
mv --backup=t 移動元 移動先

20151112_000002

[root@test-centos7 ~]# ls -l /work7
合計 0
[root@test-centos7 ~]# ls -la /work/test.txt
-rw-r--r--. 1 root root 108  7月  7 20:09 /work/test.txt
[root@test-centos7 ~]#
[root@test-centos7 ~]# # ファイルをコピー(同名ファイル無し)
[root@test-centos7 ~]# \cp --backup=t /work/test.txt /work7
[root@test-centos7 ~]#
[root@test-centos7 ~]# ls -l /work7
合計 4
-rw-r--r--. 1 root root 108 11月 12 05:12 test.txt
[root@test-centos7 ~]#
[root@test-centos7 ~]# ls -l /work/test.py
-rw-r--r--. 1 root root 2223 10月 27 07:10 /work/test.py
[root@test-centos7 ~]#
[root@test-centos7 ~]# # ファイルをコピー(同名ファイル有り)
[root@test-centos7 ~]# \cp --backup=t /work/test.py /work7/test.txt
[root@test-centos7 ~]#
[root@test-centos7 ~]# ls -l /work7
合計 8
-rw-r--r--. 1 root root 2223 11月 12 05:13 test.txt
-rw-r--r--. 1 root root  108 11月 12 05:12 test.txt.~1~
[root@test-centos7 ~]#
[root@test-centos7 ~]# # mvでも同等の処理が出来る
[root@test-centos7 ~]# ls -l /work/test.rc
-rw-r--r--. 1 root root 2590 10月 28 21:31 /work/test.rc
[root@test-centos7 ~]# \mv --backup=t /work/test.rc /work7/test.txt
[root@test-centos7 ~]# ls -l /work7
合計 12
-rw-r--r--. 1 root root 2590 10月 28 21:31 test.txt
-rw-r--r--. 1 root root  108 11月 12 05:12 test.txt.~1~
-rw-r--r--. 1 root root 2223 11月 12 05:13 test.txt.~2~
[root@test-centos7 ~]# ls -l /work/test.rc
ls: /work/test.rc にアクセスできません: そのようなファイルやディレクトリはありません

 

ファイル名末尾にタイムスタンプを付与する場合は以下のようにする。

cp --backup --suffix=.$(date +%Y%m%d_%H%M%S) コピー元 コピー先
mv --backup --suffix=.$(date +%Y%m%d_%H%M%S) 移動元 移動先

 

こちらの場合、コピー先の既存ファイル名を変更する(上書きする既存のファイル名をバックアップする)という動作のため、厳密な動きはWindowsの動作とは異なっているが、代替手段としては使えるのではないだろうか?

Microsoft Windows 10 Professional (32bit/64bit 日本語版 USBフラッシュドライブ) Microsoft Windows 10 Professional (32bit/64bit 日本語版 USBフラッシュドライブ)

Windows(PowerShell)でプログラムをnohupのようにバックグラウンド実行させる

$
0
0

だいぶ前に、Windows上でnohupのようにプログラムをバックグラウンド実行させられないか調べた事があった。
Windowsでnohup相当の処理を行わせるには、『-AsJob』パラメーターを利用するか、PowerShellに用意されている『Start-Job』コマンドを利用する。
コマンドによっては「-AsJob」はサポートしていないので、基本的に『Start-Job』で対応する事が多そうだ。

Start-Jobコマンドは、基本的に以下のように実行する。

Start-Job -ScriptBlock { 実行コマンド }

もしくは

Start-Job { & 実行コマンド }

 

Windows PowerShell実践システム管理ガイド 第2版 Windows PowerShell実践システム管理ガイド 第2版

PowerShellでリストボックスを使ったリモートデスクトップ(RDP)自動接続スクリプト

$
0
0

今までに、SSHでの選択型の自動ログインについてはTeratermマクロPythonのスクリプトを作ってみたりしたが、そういえばRDPの接続ではやってないなぁ…
と思ったので、簡素なものではあるがPowerShellで作ってみた。

まぁ、転職するので今後Windowsサーバを仕事で使うことがあるのやら不明だけど。
次のクライアントMacだし。

作りは、ホストのIPアドレスやらユーザ、パスワードを記述した「host.list」とスクリプト本体である「RDP_CONNECT.ps1」の2つ。
同じディレクトリ配下においておく。

1.host.list

「host.list」については、今まで書いたTeratermマクロなどと同じく、以下のようにカンマ区切りで作成している。
Azureなどへの接続でポート番号を指定する必要がある場合は、IPアドレスの後ろに普通に記述する。

●host.list

# HOST_NAME, HOST_IP, HOST_USER, HOST_PASS
テスト1,172.28.0.1,test,test
テスト2,172.28.0.2,test,test
テスト3,172.28.0.3,test,test
テスト4,172.28.0.4:4444,test,test
テスト5,172.28.0.5,test,test
テスト6,172.28.0.6:6666,test,test
テスト7,172.28.0.7,test,test

2.RDP_CONNECT.ps1

スクリプト本体。
リストボックスの作成部分についてはこちらを参考に、RDPの接続部分についてはこれをまんま使った。

●RDP_CONNECT.ps1

################
# - Function - #
################
function ListBox($FOREACH_HOST_LIST)
{
    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") 

    $objForm = New-Object System.Windows.Forms.Form
    $objForm.Text = "RDP自動接続"
    $objForm.Size = New-Object System.Drawing.Size(300,200)
    $objForm.StartPosition = "CenterScreen"

    $objForm.KeyPreview = $True
    $objForm.Add_KeyDown({if ($_.KeyCode -eq "Enter")
        {$x=$objListBox.SelectedIndex;$objForm.Close()}})
    $objForm.Add_KeyDown({if ($_.KeyCode -eq "Escape")
        {$objForm.Close()}})

    $OKButton = New-Object System.Windows.Forms.Button
    $OKButton.Location = New-Object System.Drawing.Size(75,120)
    $OKButton.Size = New-Object System.Drawing.Size(75,23)
    $OKButton.Text = "OK"
    $OKButton.Add_Click({$x=$objListBox.SelectedIndex;$objForm.Close()})
    $objForm.Controls.Add($OKButton)

    $CancelButton = New-Object System.Windows.Forms.Button
    $CancelButton.Location = New-Object System.Drawing.Size(150,120)
    $CancelButton.Size = New-Object System.Drawing.Size(75,23)
    $CancelButton.Text = "Cancel"
    $CancelButton.Add_Click({$objForm.Close()})
    $objForm.Controls.Add($CancelButton)

    $objLabel = New-Object System.Windows.Forms.Label
    $objLabel.Location = New-Object System.Drawing.Size(10,20)
    $objLabel.Size = New-Object System.Drawing.Size(280,20)
    $objLabel.Text = "接続先のコンピュータを選択してください:"
    $objForm.Controls.Add($objLabel) 

    $objListBox = New-Object System.Windows.Forms.ListBox
    $objListBox.Location = New-Object System.Drawing.Size(10,40)
    $objListBox.Size = New-Object System.Drawing.Size(260,20)
    $objListBox.Height = 80

    Foreach($i in $FOREACH_HOST_LIST) {
        [void] $objListBox.Items.Add($i)
        }

    $objForm.Controls.Add($objListBox)
    $objForm.Topmost = $True
    $objForm.Add_Shown({$objForm.Activate()})
    [void] $objForm.ShowDialog()

    $x
    }

function RDPConnect($CONNECT_IP, $CONNECT_USER, $CONNECT_PASS)
{
    # Cmdkey用に、接続先情報にポート番号が指定されている場合は除外する
    $CMDKEY_CONNECT_IP = $CONNECT_IP | %{ $_.Split(":")[0]}

    Cmdkey.exe /generic:TERMSRV/"$CMDKEY_CONNECT_IP" /user:"$CONNECT_USER" /pass:"$CONNECT_PASS"
    Start mstsc /v:$CONNECT_IP
    Timeout 5
    Cmdkey.exe /delete:TERMSRV/$CMDKEY_CONNECT_IP
}

############
# - Main - #
############

# 『host.list』PATH取得
$SCRIPT_PATH = Split-Path $myInvocation.MyCommand.path
$LIST_FILE = Join-Path $SCRIPT_PATH "host.list"

# 空配列の作成
$HOST_NAME_LIST = @()
$HOST_IP_LIST   = @()
$HOST_USER_LIST = @()
$HOST_PASS_LIST = @()

# 『host.list』読込み
Foreach ($i in Get-Content $LIST_FILE) {
    # 空行・コメント行を無視する
    If (($i -eq "") -Or ($i.substring(0,1) -eq "#")) {
        Continue
        }

    # 変数へ代入
    $HOST_NAME      = $i | %{ $_.Split(",")[0]}
    $HOST_IP        = $i | %{ $_.Split(",")[1]}
    $HOST_USER      = $i | %{ $_.Split(",")[2]}
    $HOST_PASS      = $i | %{ $_.Split(",")[3]}

    # 配列へ代入
    $HOST_NAME_LIST = $HOST_NAME_LIST + $HOST_NAME
    $HOST_IP_LIST   = $HOST_IP_LIST + $HOST_IP
    $HOST_USER_LIST = $HOST_USER_LIST + $HOST_USER
    $HOST_PASS_LIST = $HOST_PASS_LIST + $HOST_PASS
    }

# リストボックスを呼び出し、SeletedIndexを取得する
$SELECT_INDEX_NO = ListBox($HOST_NAME_LIST)

# 何も選択しなかった場合は処理を終了する
If ($SELECT_INDEX_NO -eq $null) {
    exit
    }

# RDP接続を行う
RDPConnect $HOST_IP_LIST[$SELECT_INDEX_NO] `
           $HOST_USER_LIST[$SELECT_INDEX_NO] `
           $HOST_PASS_LIST[$SELECT_INDEX_NO]

 

念のため、ファイルはここにあげておいた。

動くサンプルで学べる Windows PowerShell コマンド&スクリプティングガイド PowerShell 4.0対応 動くサンプルで学べる Windows PowerShell コマンド&スクリプティングガイド PowerShell 4.0対応

Pythonによるssh自動接続用スクリプト(試作) タイムスタンプ付きログ取得対応版

$
0
0

先日から作成しているPythonでの選択肢型ssh自動接続スクリプト、なんとかタイムスタンプ付きのログを取得出来るよう改良した。
まぁ、一時ファイルを作成してタイムスタンプを付与、しかもtailのラッパースクリプトとして動作させているので、あまり納得はいってないんだけど…一応動くし、まぁいいか。どうせMacかLinuxでしか動かさないし。

1.host.list

host.listについては、前回作成した内容から変わらない。

●host.list

# SSHAutoLogin.ttl用 ログインホスト設定ファイル
# 左から順に、以下の内容を記述していく。
# HOST_NAME(任意の名称。接続するホストの選択時やログ名に利用する。必須。)
# HOST_IP(ホストのIPアドレス。接続時に利用する。必須。)
# KEY_FILE(鍵ファイルの設置PATH。ない場合は空欄で記述。)
# HOST_ROOT_USER(管理者ユーザ名。ログインユーザを設定してスイッチする場合はrootユーザを設定。必須。)
# HOST_ROOT_PASS(管理者ユーザパスワード。必須。)
# HOST_USER(ログインユーザ名。管理者ユーザで直接ログイン出来る場合は不要。)
# HOST_PASS(ログインユーザパスワード。管理者ユーザで直接ログイン出来る場合は不要。)
# SUDO_FLAG(スイッチ文を「sudo su -」とするか否か。何かしら(0でも1でも)入力すると有効になる。スイッチ時のコマンドが「su -」の場合は不要)

# HOST_NAME, HOST_IP, KEY_FILE, HOST_ROOT_USER, HOST_ROOT_PASS, HOST_USER, HOST_PASS, SUDO_FLAG

# CentOS(「su -」)でスイッチする例
Test-CentOS1,172.28.0.101,,root,password,test,password

# CentOS(「su -」)でスイッチせずに直接ログインする例
Test-CentOS2,172.28.0.102,,root,password

# Ubuntu(sudo su -)でスイッチする例
Test-Ubuntu1,172.28.0.103,,test,password,test,password,1

# AWSテスト
AWSテスト,XXX.XXX.XXX.XXX,/tmp/test.pem,centos,

2.ssh_connect.py

ssh_connect.pyについては、Teratermログのようなタイムスタンプ付きのログを取得させるようにした。

●ssh_connect.py

#! /usr/bin/python
# -*- coding: utf-8 -*-
# +-------------------------------------------+
# +                                           +
# +                                           +
# +-------------------------------------------+

##################
# モジュール読込 #
##################
from __future__ import division  #You don't need this in Python3
import curses
from math import *
import os
import pexpect
import locale
locale.setlocale(locale.LC_ALL, "")
from datetime import datetime
import subprocess

########
# 関数 #
########

def ssh_connect(line_no):
    # 接続時に使用する情報を取得
    connect_host_name      = "".join(map(str,host_name_list[line_no]))
    connect_host_ip        = "".join(map(str,host_ip_list[line_no]))
    connect_key_file       = "".join(map(str,key_file_list[line_no]))
    connect_host_root_user = "".join(map(str,host_root_user_list[line_no]))
    connect_host_root_pass = "".join(map(str,host_root_pass_list[line_no]))
    connect_host_user      = "".join(map(str,host_user_list[line_no]))
    connect_host_pass      = "".join(map(str,host_pass_list[line_no]))
    connect_sudo_flag      = "".join(map(str,sudo_flag_list[line_no]))

    # 一時ログファイル、正規ログファイル定義
    pid          = str(os.getpid())
    tmp_log      = tmp_dir + '.' + pid + '.' + connect_host_name + '.' + now_time
    terminal_log = log_dir + now_time + '_' + connect_host_name + '.log'

    # ログインユーザーの指定有無を確認
    if connect_host_user == "":
        connect_user = connect_host_root_user
        connect_pass = connect_host_root_pass
    else:
        connect_user = connect_host_user
        connect_pass = connect_host_pass
    if connect_key_file == "":
        foo = pexpect.spawn('ssh -o "StrictHostKeyChecking=no" %s@%s' % (connect_user, connect_host_ip))
    else:
        foo = pexpect.spawn('ssh -o "StrictHostKeyChecking=no" -i %s %s@%s' % (connect_key_file, connect_user, connect_host_ip))

    # ログの取得開始
    foo.logfile_read = open(tmp_log,"w")

    log_tail = 'tail -f ' + tmp_log
    log_awk  = 'gawk \'{ print strftime("[%Y/%m/%d %H:%M:%S]") " " $0 } {system (" ")}\' >' + terminal_log

    get_log_command  = log_tail + ' | ' + log_awk + ' &'
    #subprocess.Popen(get_log_command, shell=True)
    os.system(get_log_command)

    if not connect_pass == "":
        foo.expect(['.*ssword:','パスワード:'])
        print foo.before.rstrip()
        print foo.after.rstrip()
        foo.sendline(connect_pass)
    if not connect_host_user == "":
        foo.expect(['$','#'])
        print foo.before.strip()
        print foo.after.strip()
        foo.sendline('su - %s' % (connect_host_root_user))

        foo.expect(['.*ssword:','パスワード:'])
        print foo.before.strip()
        print foo.after.strip()
        foo.sendline(connect_host_root_pass)
    foo.interact()
    #os.system('kill ' + log_pid + ' &')
    os.system('ps -fC "tail" | grep "' + log_tail + '" | awk \'{ print $2\'} | xargs kill')
    os.remove(tmp_log)

############
# 設定関連 #
############
max_row      = 20
list_file    = '/root/data.csv'
command_file = ''
log_dir      = '/work/'
tmp_dir      = '/tmp/'
now_time     = datetime.now().strftime('%Y%m%d_%H%M%S')

##################
# curses関連設定 #
##################
# リスト表示件数
screen        = curses.initscr()
curses.noecho()
curses.cbreak()
curses.start_color()
screen.keypad( 1 )
curses.init_pair(1,curses.COLOR_BLACK, curses.COLOR_CYAN)
highlightText = curses.color_pair( 1 )
normalText    = curses.A_NORMAL
screen.border( 0 )
curses.curs_set( 0 )
box           = curses.newwin( max_row + 2, 100, 1, 1 )
box.box()

##################
# リスト情報取得 #
##################
f = open(list_file)
line = f.readline()
i = 0
host_name_list      = []
host_ip_list        = []
key_file_list       = []
host_root_user_list = []
host_root_pass_list = []
host_user_list      = []
host_pass_list      = []
sudo_flag_list      = []
while line:
    line = line.strip()
    # コメント・空行を除外
    if line.startswith( "#" ) or len( line ) == 0:
        line = f.readline()
        continue
    # リストの各要素を取得
    line_column = len( line.split(',') )
    if line_column == 5:
        host_name      = line.split(',')[0]
        host_ip        = line.split(',')[1]
        key_file       = line.split(',')[2]
        host_root_user = line.split(',')[3]
        host_root_pass = line.split(',')[4]
        host_user      = ""
        host_pass      = ""
        sudo_flag      = ""
    elif line_column == 7:
        host_name      = line.split(',')[0]
        host_ip        = line.split(',')[1]
        key_file       = line.split(',')[2]
        host_root_user = line.split(',')[3]
        host_root_pass = line.split(',')[4]
        host_user      = line.split(',')[5]
        host_pass      = line.split(',')[6]
        sudo_flag      = ""
    elif line_column == 8:
        host_name      = line.split(',')[0]
        host_ip        = line.split(',')[1]
        key_file       = line.split(',')[2]
        host_root_user = line.split(',')[3]
        host_root_pass = line.split(',')[4]
        host_user      = line.split(',')[5]
        host_pass      = line.split(',')[6]
        sudo_flag      = line.split(',')[7]
    else:
        curses.endwin()
        print "リストに誤りがあります。"
        print line
        exit(1)
    host_name_list      += [[host_name]]
    host_ip_list        += [[host_ip]]
    key_file_list       += [[key_file]]
    host_root_user_list += [[host_root_user]]
    host_root_pass_list += [[host_root_pass]]
    host_user_list      += [[host_user]]
    host_pass_list      += [[host_pass]]
    sudo_flag_list      += [[sudo_flag]]
    line = f.readline()
f.close
row_num = len( host_name_list )

##############
# リスト表示 #
##############
pages = int( ceil( row_num / max_row ) )
position = 1
page = 1
for i in range( 1, max_row + 1 ):
    if row_num == 0:
        box.addstr( 1, 1, "There aren't host_name_list", highlightText )
    else:
        if (i == position):
            box.addstr( i, 2, str( i ) + " - " + "".join(map(str,host_name_list[ i - 1 ])), highlightText )
        else:
            box.addstr( i, 2, str( i ) + " - " + "".join(map(str,host_name_list[ i - 1 ])), normalText )
        if i == row_num:
            break
screen.refresh()
box.refresh()

##########################
# ホスト選択画面キー操作 #
##########################
x = screen.getch()
while x != 27:

    # 下キー押下時の動作
    if x == curses.KEY_DOWN:
        if page == 1:
            if position < i:
                 position = position + 1
             else:
                 if pages > 1:
                    page = page + 1
                    position = 1 + ( max_row * ( page - 1 ) )
        elif page == pages:
            if position < row_num:
                position = position + 1
        else:
            if position < max_row + ( max_row * ( page - 1 ) ):
                 position = position + 1
             else:
                 page = page + 1
                 position = 1 + ( max_row * ( page - 1 ) )
     # 上キー押下時の動作
     if x == curses.KEY_UP:
         if page == 1:
             if position > 1:
                position = position - 1
        else:
            if position > ( 1 + ( max_row * ( page - 1 ) ) ):
                position = position - 1
            else:
                page = page - 1
                position = max_row + ( max_row * ( page - 1 ) )

    # 左キー押下時の動作
    if x == curses.KEY_LEFT:
        if page > 1:
            page = page - 1
            position = 1 + ( max_row * ( page - 1 ) )

    # 右キー押下時の動作
    if x == curses.KEY_RIGHT:
        if page < pages:
            page = page + 1
            position = ( 1 + ( max_row * ( page - 1 ) ) )

    # Enter押下時(決定)の処理
    if x == ord( "\n" ) and row_num != 0:
        screen.erase()
        screen.border( 0 )

        curses.endwin()
        ssh_connect(position - 1)
        exit()

    box.erase()
    screen.border( 0 )
    box.border( 0 )

    for i in range( 1 + ( max_row * ( page - 1 ) ), max_row + 1 + ( max_row * ( page - 1 ) ) ):
        if row_num == 0:
            box.addstr( 1, 1, "There aren't host_name_list",  highlightText )
        else:
            if ( i + ( max_row * ( page - 1 ) ) == position + ( max_row * ( page - 1 ) ) ):
                box.addstr( i - ( max_row * ( page - 1 ) ), 2, str( i ) + " - " + "".join(map(str,host_name_list[ i - 1 ])), highlightText )
            else:
                box.addstr( i - ( max_row * ( page - 1 ) ), 2, str( i ) + " - " + "".join(map(str,host_name_list[ i - 1 ])), normalText )
            if i == row_num:
                break

    screen.refresh()
    box.refresh()
    x = screen.getch()

curses.endwin()
exit()

 

うーん、処理の仕方が汚いのが気になるけど、とりあえずはこれでいいか…
そのうち直そう。

ハイパフォーマンスPython ハイパフォーマンスPython
Viewing all 1028 articles
Browse latest View live