それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

php のエルビス演算子を初期化以外の用途で使ったら・・・

エルビス演算子が便利だけど。

三項演算子の省略形 elbis operator が便利だけど

<?php
$a[0] = $a[0] ?: 10 ;
var_dump($a);

// array(1) {
//  [0]=> int(10)
//}

変数初期化チェックがシンプルになって嬉しいよね。empty 相当だよねーってウキウキして empty の代わりの使ってみたり。

三項演算子を省略する使うとちょっとね。

<?php
$a[0] = empty($a['a']) ?: 10 ;
var_dump($a);
// array(1) {
//  [0]=> true
//}

そうか、true になるのか。三項演算子の省略形としては「初期化」以外で使うと絶対ダメですね。。。

一時的にaliasをオフ無効にする バックスラッシュ

一時的にalias をオフにしたいとき

grep や ls などを使っていて、一時的にalias をオフにしたいことないですか?

私は結構たくさんあります。 grep や ls にいっぱいオプションを付けていて普段はそれを使っているのですが、素のgrep がほしいときはある。

そんなときは back slash を入れます。

\grep . -R 

このような、エイリアスがあったとしても、素のgrep が動いてくれます。

takuya@:www-data$ alias grep
alias grep='grep -i -E -a --color=auto -n '

これを知って、安心して rm や ls までどんどん alias にしていくことが出来ました。

不必要に エイリアスが呼び出されてしまわないように バックスラッシュをつけるのが良いです。

ただし、同名の関数が定義されているときは関数が優先されます。

シェルから一時的に使うと便利。

バックスラッッシュは、エイリアスがあるために意図した動作にならないときに、対話的prompt で使うと便利です。本当に便利です。

互換性を維持する目的であれば フルパス

alias しまくってると不意に動作することがあるので、シェルスクリプトにバックスラッシュを書きたくなると思います。別環境に持っていくときに alias が発動しないようにバックスラッシュを付与したスクリプトファイルにしても構わないのですが。。。。

互換性を目的にするのであれば、バックスラッシュよりもフルパスが好ましいと思います。

## これはalias発動するのでポータビリティに向いてない。
ls *.jpg | grep aaa| xargs identify

## これだと、alias なしで実行される。が、function grep {   ... } があればそちらが使われてしまう。
## またPATH優先順位にも左右されてしまう。
ls *.jpg | \grep aaa| xargs identify

##  フルパスで指定が無難
ls *.jpg | /bin/grep aaa| xargs identify

このように、シェルのコマンドの優先度を考えたら、ポータビリティを維持する目的でではバックスラッシュは向いていません。

2019-08-23

互換性についての記述を追加。

MySQLの基本的コマンド(ユーザ・DB・権限・パスワード)の設定削除作成の早見表 -- sql 版

MySQLをぱぱっと管理したときに困らないように

データベース作成したり削除したりで困らないように、チートシート的にコピペで使えるようなものを用意しておきます。

ユーザーの新規作成・削除・パスワードを変更などはよく使うのでどこかにメモっておくといい感じ。

ユーザーの確認

ユーザーの一覧を見ます。

select User,Host, Password from mysql.user;

データベース一覧

データベース表示するには、専用コマンド show databaseを使います。

show databases ;

テーブル一覧

テーブル一覧は、専用コマンド show tabales が便利です。

use my_db;
show tables ;

ユーザー作成

ユーザー作成は create user をつ使います。

create user 'your name' identified by 'your pass'

権限の追加

grant all on my_db.* to your_name@'%'

権限の確認

権限を委譲(grant) したら専用コマンドで権限の割当を確認します。

show grants for your_name;

権限の反映

データベースを作成したりユーザーを割り当てたあとは、権限(Privileges)を更新します。

FLUSH PRIVILEGES 

ペアで覚える

作成と削除はペアで使うことが多いのでまとめて掲載しておきます。

データベースの作成・削除・確認

create database YOUR_DB_NAME;
show databases;
drop database YOUR_DB_NAME;

作成・削除と確認はペアで覚えておかないと複数個作ったり消したりしてるとパニックになるので最初に覚えること

ユーザ作成・削除

作成削除はまとめて覚えておくといいので create user と drop user はペアで掲載しておきます。

create user 'your name' identified by 'your pass'

select User,Host, Password from mysql.user;

select User,Host, Password from mysql.user where User like  '%yourname%'

drop user 'your name' 
drop user takuya@'hostoname'

パスワードの変更

ALTER USER 'user'@'hostname' IDENTIFIED BY 'this_is_my_new_password';

設定したパスワードを忘れた場合は、パスワードを再設定するときや紛失・盗難でパスワードを変更する必要があるとき。といっても大抵の場合では、初期設定の時点でメモを忘れてパスワードを紛失するんだけど。

権限の追加削除と確認

grant all on my_db.* to your_name@'%'
revoke all on my_db.* from your_name@'%'

権限削除って余り使わないかも。Allつけておいて不要な権限だけ削除する感じ? それだったら必要な権限だけつけたら良いわけで。

root 権限をもつユーザーの作成

 grant all on *.* to 'takuya'@'%'  WITH GRANT OPTION;

GRANTをGRANTする。権限のGRANTを許可できるroot と同じ管理者権限を付与するには、with grant option をつける

2020-08-04

mysql のパスワード忘れの場合の、パスワードの初期化・変更を追記。

2021-03-30

revoke に記述ミスがあったので修正。

2021-05-28

検索エンジンにこのエントリが無視されるので、微妙にキーワードを追加する。

フルカラーと白黒のプリントやコミックスのzipを判別する

以前、画像の白黒判定をやった

takuya-1st.hatenablog.jp

白黒判定が出来るから、スキャンした画像が「プリント」か「雑誌」か判定していけば便利なんじゃないかと

ScanSnap

ScanSnap でスキャンしたときに、学校のプリントか、教科書やカラー資料か判定して仕分けたい。

http://amazon.jp/dp/B00T2B5L52/?tag=takuya-hateblo-22

富士通 ScanSnap iX500 (A4/両面)

富士通 ScanSnap iX500 (A4/両面)

zip にしておけば、簡単に判別できそう

機械学習とか使わなくてもプリント程度なら、ぱぱっと判定できた。

これでzipコミックスを仕分けできそうで便利。

ScanSnapで白黒を自動調整しておけば確実にモノクロと判別できて楽だった。

#!/usr/bin/env ruby
#
#


dirname  = Dir.pwd


require 'tmpdir'
require 'pry'
require "tmpdir"

def check( f_name )
  # binding.pry

  # Dir.chdir dirname

  is_color_comic = false
  Dir.mktmpdir("check-color-", '/tmp') do |dir|

    cmd = %%unar -o "#{dir}"   "#{f_name}"  %
    # puts cmd
    `#{cmd}`

    list = Dir.glob("#{dir}/**/*")
    # puts list
    list = list.grep(/jpe?g|png|gif|png/).sort
    unless list.size > 10 then
      return false
    end

    mid =  ((list.size.to_f-1)*0.666).floor
    names = list.slice( (mid-2)..(mid+2) )
    puts names

    color_page = names.map{|e|
      cmd = <<-"EOS".gsub(/\s+/, ' ').gsub(/^\s+/,'')
      convert '#{e}' \
        -colorspace HSB \
        -separate -delete 0 \
        -fx "u*v" -blur 2x2 \
        -threshold 30% \
        -format '%[fx:mean]\n' info:
      EOS
      # p cmd
      ret = `#{cmd}`
      puts ret.to_f
      (ret.to_f  > 0 ) ? 1 : 0

    }.inject(0){|sum,x| sum + x }
    puts color_page
    is_color_comic = color_page  > 3
  end

  return is_color_comic
end

path = './*.zip'
Dir.glob(path).sort.reverse.each{|e|
  # begin
    if File.directory? e
      next
    end

    puts e
    ret = check(e)
    if ret then
      puts :color
      `sudo mv "#{e}" 'プリント' `
    end
}

node.jsを野良ビルドした記録

node を野良ビルドした

debian jessie の node が古いので野良ビルドした。 jessie そろそろ捨てるけど、ちょっと急ぎで node 使う必要があったので。

コンパイルとインストー

checkinstall を使った

sudo apt install checkinstall 

作業ログ

wget https://nodejs.org/dist/v6.11.1/node-v6.11.1.tar.gz
tar zxvf node-v6.11.1.tar.gz
cd node-v6.11.1
./configure
checkinstall

configurepython 3.6 で動くかよ! って怒られたので pyenv で変えた

pyenv local system
./configure --prefix=/home/takuya/.usr/local

raspberry pi で初期ユーザー pi 以外のユーザーを自動ログインする。

raspi W 届いた!

raspi W を買ったので初期設定した。

ユーザー takuya を追加して代わりに使うことにした

ユーザー pi は絶対狙われるので、ssh がグルーバルから接続できないように設定して、ログインは最低限した。

自動ログインユーザーを決める方法を変えた

自動ログインのユーザーを交換するには、 raspi-confg などでは出来なくて /etc を弄る必要があった。

/etc/lightdm/lightdm.conf

   113 #greeter-setup-script=
    114 #session-setup-script=
    115 #session-cleanup-script=
    116 #autologin-guest=false
    117 autologin-user=takuya
    118 #autologin-user-timeout=0
    119 #autologin-in-background=false
    120 #autologin-session=UNIMPLEMENTED
    121 #exit-on-failure=false
    122
    123 #

これで、raspi で自動ログインするユーザーを決められて、takuya ユーザーで自動ログイン出来るようになった。

omxplayer を ssh 経由で呼び出すのにとても重要だった。

MySQL の blob型に入ったStringを文字列(utf-8)にして取り出す。

blob に長い文字列が入ってます。

mysql で varchar や textを使えばいいのに、blob で文字列を埋め込んでいるソースコードがありまして。

そこに入ってる文字列を取り出しても blob なので hex になってるだけです。これを文字列として SELECT したい

convertを使えば出来る

select convert (path using utf8)  from my_table;

blob を使うのはutf-8MySQLの文字列変換を抑制させるのにバッドノウハウとしてよく使われていたらしい。

convert コマンドで String に出来るのでまぁいいか。

SQLで連番を作成や配列をカラム・行に展開する

SQL で連番を扱うときに

SQL で連番を扱うときに、数字が入った配列が有るととても便利です。ただしソレを作成するのは不便です。

0..9

これを、次のようなテーブル行に展開したい。

:id
0
1
2
3
4
5
6
7
8
9

SQLで配列を展開するように行にする。

select 0
 union select 1
 union select 2
 union select 3
 union select 4
 union select 5
 union select 6
 union select 7
 union select 9
 union select 9
;

結果

0
----------
0
2
3
4
5
6
7
9

N個に展開してJOINすると

N個に展開して直積を取ってあげると、結構好きにテーブル展開を扱えるようになる。テーブルのピボットや、空席を調べたり欠番を埋めるのに作りやすくなる。

便利

ちょっといじれば10x10x10 の直積で

1000行作ったり出来る。なんか楽しい

select * from (
select 0 
 union select 1
 union select 2
 union select 3
 union select 4
 union select 5
 union select 6
 union select 7
 union select 9
 union select 9
) as  a
left join  (
select 0 
 union select 1
 union select 2
 union select 3
 union select 4
 union select 5
 union select 6
 union select 7
 union select 9
 union select 9
) as b
left join  (
select 0 
 union select 1
 union select 2
 union select 3
 union select 4
 union select 5
 union select 6
 union select 7
 union select 9
 union select 9
) as c
;

参考

https://stackoverflow.com/questions/1564956/how-can-i-select-from-list-of-values-in-sql-server

https://codezine.jp/article/detail/1076

0001docomoのdocomoWiFiにパソコン(iPad)接続のID/PWの確認

docomo Wifiはパソコンから使える

ありがとう、ドコモ。ドコモのWiFiはパソコンやタブレット(ipad)から使えます。

auソフトバンクが軒並み接続サポートを消していく中にあって ドコモはちゃんと接続させてくれます。

しかも電波も管理もしっかしてて確実につながる ソフトバンクみたいに「とりあえず」のWiFiとは質が違う。

ドコモ契約者は無料

無料で使える。ただし設定が必要。

0001docomo はSIMカード認証なので、パソコンから使うには設定がひつよう

id/password は下記サイトから

パスワードとログインユーザ名は、ドコモIDとは別管理になっていて、そのID/PWのペアはMyDocomoから確認することが出来る。

https://www.nttdocomo.co.jp/mydocomo/sp_setting/index.html#accordion-8

ここから確認できる。

f:id:takuya_1st:20170703162430p:plain:w200

接続IDとパスワードを保存したら

0001docomo につなぐときに、上記サイトで書くにしたID/PWを入力すると、とても簡単につながる。

月額300円のWiFiサービスでは優秀

月額300で使えるWiFiとして見た場合とても、とても優秀。

近所に電波が飛んでいたら固定回線の契約は要らないんじゃないかと思うレベル。

おまけ

公衆WiFiを使うコツ「人通りの多さを見ておく」

大勢のひとが「通過」する道路や駅コンコースの無線LANは、たくさんの人のスマホが接続しては切断したり、スマホが接続可能をチェックしている間に通り過ぎたりするので、2.4GHz電波の利用率高い。また大勢がくると、古い接続から順に親機側で切られてしまう。

1分間に30人程度が出入りしてるともう結構厳しい。もちろんここには道路を通過する車が含まれたり、電車が接近すると上客のスマホが含まれたり、バスが複数台通過すると「切断接続の嵐が吹き荒れる」・・・ってことになる。

つまり、1分間程度通信をしないと接続(認証)を切られてしまう。パソコンの接続チェックより早いタイミングで切断されてたりするので、画面上では接続になってるのに通信できないで、タイムアウト処理まで待たされて何も出来なことが有る。たとえばMacWiFiは想定外らしく全く動かなくなっておかしな動作を繰り返したりする。(再起動しないと治らない)

もしWiFiを使いたいと思ったら、2F/3Fの店舗や、地下街で店の奥側など人通りを気にした方がいいでしょうね。

また定期的な通信をすればいいので

watch -n 10 dig google.com 

などとして定期的通信をしておかないとすぐ切断されちゃう。

スマホゲでリアルタイム通信する厨房集団が現れると一気に帯域持っていかれて、電波が枯れちゃうので無線LANは途端に接続できなくなったりするので、負けないようにパケットを投げまくらないと行けない感じある。不毛だ。

pdoで文字化けを防ぐutf-8を設定する

phpMySQL(mariaDB)にアクセスすると文字化けをする

いまどき文字化けするなんて思わなかった。古いデータベースだし mysql 関数でやってるやつだからなぁ

set name しなくても PDO のドライバの初期化のタイミングで文字コードを指定できるようになっている。

対策

<?php
$opts = array(
    PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
); 
$dsn = 'mysql:host=example.com;dbname=my_db',
//
$pdo = new PDO( $dsn,  'root', 'pass', $opts);

ペアになってるもの

mysqli_query mysql_query で

<?php
$sqlstr = "set NAME utf8";
mysqli_query( $dbh, $sqlstr );

MySQLのテーブル設定はこんな感じ。

) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci 

php7 で非推奨になったmysql_connect関連のmysql関数を対応する(mysqli

php7 から mysql_connect が非サポートになりました。

いまどきPDO使ってないとかありえないんですけど。まぁmysql_connect を使ってるプログラムが動いてることも多いわけです。

今回はこの対応をしたので、誰かの役に立てばいいのでメモっておきます。

mysql_connect は使えなくなりました。(←正しくは

php_mysql拡張機能が標準バンドルされなくなった。なので標準インストールでは使えない。 だったら、追加インストールすればいいんじゃね?まぁそういうことです。

でも、それは最終手段に確保がベターな予感ある。php 本体のアップデートの都度に拡張機能をアップデートするのは結構大変で、php_magick をビルドインストしてたときは1ヶ月に1度くらいphpアップデートに併せてビルドしてた記憶有るし。なので、php_mysql のビルドインストはやめたほうが良いだろうっって判断しました。

mysqli への切り替え

php7 のmysql_connect の対応は、複数の選択肢があります

  • mysqli_connect へ
  • new mysqli へ
  • new pdo へ
  • php_mysql をインストール(←前述の理由で見送り

最初のが一番簡単なので、まず考えるのは mysqli_connect → mysqli_connect の書き換えではないでしょうか。2つは、同じ関数とリソース型を扱う設計で引数も「似ています」(同じではない)

二つ目はクラスです。mysqli は基本的にオブジェクトで作られているので new でインスタンスを生成し、それを使うようになっています。

三つ目はPDOです。インタフェースが異なるので移行とはすなわち書き直しとなります。

mysqli への書き換え1

connect だけは mysql も mysqliもほとんど同じです。

mysqli_connect("127.0.0.1", "my_user", "my_password", "my_db");
mysql_connect('localhost', 'mysql_user', 'mysql_password');

引数同じなのでほとんど変える必要がない。楽ちん

escape 関連

escape をしてる場合は、選択肢が2つ有る。

mysql_real_escape_string
mysqli::real_escape_string 
mysqli_real_escape_string

前者がクラス・メソッドで後者が インスタンスを必要とする。結局はインスタンスが必要になるので、手間はあんまり変わらない。

<?php
//
mysql_real_escape_string($str);
//
$mysqli_instance->real_escape_string( $str );
mysqli_real_escape_string( $mysqli_resouce , $str )

query 関連

クエリ発行の部分もmysqli ではインスタンス(リソース)が必要になるので、少し書き直しが必要。

mysql_query(  $str )

mysqli_query( $resouce, $str)

クエリ発行後は殆ど変わらなかった。

connect 数の上限

mysqli と mysql の書き換えを行ったとに、実験していると気付いたのですが。

mysql と mysqli にはインタフェースは似ていてもコネクションの管理や再利用が全然違っていて、そのままのロジックだと、コネクション数オーバーしてしまった。編集前では 全然問題なかった。

mysql_connect で接続つくって潰し、作って潰しで2000接続くらい作れてたのに、mysqli_connect だと全然動かないの。上限に達しちゃう。もしかしたら接続を再利用してくれないと思う。

なので接続をきっちり管理してやる必要があった。そこはハマった。

なので関数を書き換えたら問題なく動くって思わないほうが良い。

mysql 関数群と mysqli 関数群は似ているけど全然別物!ってことを念頭に起きながら、書き換える必要がありました。

最終的に次のような関数を書く羽目になったので、コネクション数の管理は別物だと思うことにしました。

<?php
function MyConnect  (){
    global $con;
    if ( !$con){ return $con;}
    return $con = mysqli_connect("127.0.0.1", "my_user", "my_password", "my_db");
}

MyConnect()

csh 系で 日本語 文字コードを設定する

csh 系のシェルを使ってた

FreeBSDにログインする機会があり、文字コードで詰まった。

文字コード環境変数をセットするには setenv を使うらしい。

 setenv LANG ja_JP.UTF-8

これで日本語が正しくなった。

pv pipe viewer をcaptureする

プロセスの進捗を見る pv で

pv はプロセスパイプを通過したバイト数をみて、進捗を見ることが出来るのですが。

pv の出力をスクリプトから取りたい

pv の output は stderr に書かれるのだけれど、それをキャプチャリングしたいなと思ったら。。。結構面倒くさいのです。

pv は プロセスの起動をアレコレしているっぽくて、ターミナルのFdに直接書いてるわけではなさそうなのです. たぶん tty とかに直接かいてるんじゃないかな。

-f オプションを使う。

オプションを使うことでstderr に書き出す事ができる。

pv -f hdd.img | lzop ...  2> out.log

ruby とかで spawn / fork するには

r,w= IO.pipe
cmd = 'pv -f  IMG_3200.MOV | cat - > /dev/null'
puts cmd
pid =  Process.fork do
  r.close
  STDERR.reopen w
  Process.exec cmd
end
s = ''
w.close
while s = r.read(100) do
  puts s
end

Process.waitpid pid

こうすれば、進捗を変数に取り出すことが出来た。あーこれはハマるわ。。。 ffmpeg の進捗をもっと簡単に取る方法ないのかな。。。。

関連資料

http://takuya-1st.hatenablog.jp/entry/2017/03/06/172644

参考資料

http://www.ivarch.com/programs/quickref/pv.shtml

WindowsのSJISのファイルがUTF-8で化けるので一気に置換するスクリプト

windowsから来たZipファイルを展開したら

文字コードがグチャグチャーって化けるのでした。辛い。

文字コードを修正するスクリプトをぱぱっと書いた

conv_file_name.sh -v -n path/to/*.pdf
conv_file_name.sh -v  path/to/*.pdf

nkf があれば何とか出来るんだけけれど結構面倒くさいのでファイル名を変化するシェルコマンド書いた。

あれこれ冗長なのと細かいエラー処理をしてないのであらゆる場面に対応できるかと言われれば多分出来ないけど。

とりあえず、これでいいや

conv_file_name.sh

#!/usr/bin/env bash

function mv_conv(){
  src=$1
  dst="$( echo -n $src | nkf -w )"

  if [[ "$src" == "$dst" ]] ; then
    return
  fi
  if [[ $3 == 1 ]] ; then
    echo "'$src'" "'$dst'"
  fi
  if [[ $2 != 1 ]] ; then
    mv  "$src" "$dst"
  fi
}

declare FILES;
declare VERBOSE;
declare DRY_RUN;

for arg  ; do
  case $arg in
    '-n')
      DRY_RUN=1
      ;;
    '-v')
      VERBOSE=1
      ;;
    *)
      FILES+=("$arg")
  esac
done

for i in "${!FILES[@]}"; do
  file=${FILES[$i]}
  mv_conv "$file" "$DRY_RUN" "$VERBOSE"
done

SeleniumのWebDriver(chrome)からCookieを取りだしてHTTP::CookieにしたりCurlで再利用する

Selenium のWebDriverからCookieを取り出したら

Seleniumで画像をだけを取り出して保存したり、ファイルを取り出すのは不便だよね。

だけど、直接Curlで叩くのもCookieの問題でもっと不便だよね。

そこでSeleniumCookieCurlで使える形式やNetscape形式で保存したり、RubyPythonなどの http cookieクラスに変換して保存したら楽だと思ったので作ってみた。

私はスクレイピングメインなのでChromeを使っています。

Selenium からCookieを取り出してファイルに保存する。

保存する形式は次の通り。

imid=HeNFSXsHS82I7KZB9xiYkQ; expires=Thu, 06-Jun-2019 17:43:13 GMT; domain=.im-apps.net; path=/;
def save_cookie_to_cookie_jar(driver)
    s = driver.manage.all_cookies.map{|e| [
        "#{e[:name]}=#{e[:value]}" ,
        "#{e[:secure] ? 'secure; ':'' }",
        (e[:expires]||Time.now).strftime('%a, %d-%b-%Y %T GMT'),
        "domain=#{e[:domain]}" ,
        "path=#{e[:path]}" ,
    ].reject{|e| e == '' }.join("; ")

    }.join("\n")
    tmp = Dir::Tmpname.make_tmpname( 'a', '.cookie_jar.txt' )
    tmp = File.expand_path(tmp, Dir.pwd)
    open(tmp, 'w'){|f| f.puts s}
    return tmp
  end

curl で使える形式に保存してみる

## 取り出したファオルの形式は次の通り。( タブ区切り )
example.com    FALSE    /    TRUE    0    XSRF-TOKEN    ePG7sHRafqxj
  def save_cookie_for_curl(driver)
    s=  driver.manage.all_cookies.map{|e|
      [
        e[:domain],
        ((e[:domain]=~/^\./)==0).to_s.upcase,
        (e[:expires]||Time.now).to_time.to_i ,
        e[:path],
        e[:secure].to_s.upcase,
        e[:name], e[:value]
      ].join("\t")
    }.join("\n")
    tmp = Dir::Tmpname.make_tmpname( 'a', '.cookie_jar.txt' )
    tmp = File.expand_path(tmp, Dir.pwd)
    open(tmp, 'w'){|f| f.puts s}
    return tmp
  end

cookie さえなんとかすれば

スクレイピングでHTMLからデータを抜くのに、並行処理だとか、分散処理が出来て一気に楽になる。

サーバーの負荷はたしかに気になるけど、ドメインを dig って CDN 経由ならもう気にしないことにしてる。

CDNはそう簡単に落ちないし、強い。

wkhtmltopdf と組合せたり、 chrome --print-pdf と組合せたり、curl と組合せたり、Mechanizeと組合せたり、Cookieさえなんとかすれば結構楽しい世界が広がる。

関連資料

http://takuya-1st.hatenablog.jp/entry/2013/08/15/031247