xargs についてのメモ

xargs の使い方毎回忘れるので、備忘。

xargs の一般的な話は他で。

実行されるコマンドだけを列挙

xargs を利用した際に発行されるコマンドだけを列挙させるには、 -p オプションを使って、

cut -f 5 data2|tail -10|xargs -n 1 -I {} -p ./bcrypt.mac --password={}
./bcrypt.mac --password=kdsjfkldsjfkdsj?...
./bcrypt.mac --password=kdsfjdkfjkd?...

のようにする。で、実行させる場合、-p オプションを除去して、

cut -f 5 data2|tail -10|xargs -n 1 -I {} ./bcrypt.mac --password={}
$2a$10$VEA5caueTtvClPJvX3zdXuONc32pPGlPGEstkbxmpFnWIWH40WGau
$2a$10$bkPOHB3laLV9rnxERIaeneYKfDog28yPx0TilZZusedPGdbfSrH2W

のようにする。上記の例だと、bcrypt.mac コマンドの実行結果だけが出ている。

コマンド呼び出し頻度の変更

何も指定しない場合、

cut -f 5 data2|tail | xargs echo
kasjfd asdfkjfdfd sdkfjdkfjd 

こういう感じ。どうしてこうなるかというと、

cut -f 5 data2|tail | xargs -p echo
echo kasjfd asdfkjfdfd sdkfjdkfjd?...

のように処理されるから。もっと量が多い場合は、echo が2回以上呼ばれる場合もある。

毎回 echo を呼びたい場合、

cut -f 5 data2|tail | xargs -p -n 1 echo
echo kdsjfkeiasdfdaf?...
echo akksjfkdfjdkjf?...
echo kjfkdfjdkfdf?...

とする。

引数の場所を指定する

上記までのやり方だと引数は常に最後につく。場所を find コマンドのように指定したい場合、

cut -f 5 data2|tail -10|xargs -n 1 -I {} -p ./bcrypt.mac --password={}
./bcrypt.mac --password=ksjfkdjdkfj?...
./bcrypt.mac --password=kdjfdkjfdkjfd?...
./bcrypt.mac --password=kjfdkjfdkddd?...

のようにする。

さらに凝ったことがやりたい時は

Perl とかのスクリプト言語でやったほうが簡単な場合も。

cut -f 5 data2|tail -10|perl -nle '$a=`./bcrypt.mac --password=$_`;chomp($a);print "$_:$a"'
asfdsfd:$2a$10$q9B5Nthx7AqliBzY7vQdruekrDNHbw6HyVlpH9JcyjIO2Cn5.ITVq
asfdsfdfd:$2a$10$6p7SKXrJ3M.s8Z/r4u7rwe66gIyAZri3pdDz8dpex3EyrcbfpZpu6
asdfdsfdsdd:$2a$10$6Q4wlJkINHxjJAKg6ztOOOE1.vUZcqN7b2h6ZQ9DTK7NwATGmj18q
cut -f 2,5 data2|tail -10|perl -nle 'chomp;@a=split;$b=`./bcrypt.mac --password=$a[1]`;chomp($b);print "$a[0]:$a[1]:$b"'
Aさん:mcvcivc:$2a$10$x84wWkAVyFO2ppjM1ltTau9rI7XViUkbjldqhxlb6UCo99ctnyAKW
Bさん:jckjfeiedf:$2a$10$KSz0GIl5whWhRs2e9sS9AOt7DkrJOHB9lJ6iFbdgWMz2iLyxbQl3i
Cさん:kdfjkfjeij:$2a$10$xwqZpX3nJhldceSx05J78OzdLVnT0BSPp7J9xfFNYS0DHpteGQo/C

以上

heif を jpg に変換してみた

これ、Java on Linux の人は2018年時点だと意外と場合によっては苦戦するのかな?と思ったので、
バニラな Amazon Linux2 で、heif を jpg に変換する方法を省略一切なしで書いておきます。
※ その後、Amazon Linux でもまったく同じ手順で動くことを確認しました。


そのまま流せば良いだけです。

sudo su
yum install git gcc-c++ automake libtool libjpeg-devel
git clone https://github.com/strukturag/libde265.git

cd libde265
git checkout v1.0.3
./autogen.sh
./configure
make install

echo "/usr/local/lib" > /etc/ld.so.conf.d/locallib.conf
ldconfig
ldconfig -p|grep 265 # ライブラリが入ってることの確認

cd ..
git clone https://github.com/strukturag/libheif.git
cd libheif
git checkout v1.3.2
./autogen.sh
PKG_CONFIG_PATH=/usr/local/lib/pkgconfig ./configure
make install
ldconfig
ldconfig -p|grep heif   # ライブラリが入ってることの確認
exit

これで、`heif-convert` っていうサンプル実装が使えるようになります。

後は一般ユーザに戻って、

$ heif-convert IMG_0128.HEIC hoge.jpg                                                               
File contains 1 images
Written to hoge.jpg

て感じで無事変換されることが確認できると思います。
公式とかいくつかのブログ記事見た限りだと、全部このへん詳しい人が書いてるためか、
ldconfig してる例が一個も無かったんですが、これははしょられると、
環境によってはメチャはまる気がします。

これは、heif --> jpg 変換ですが、png にも変換することは出来ます。
その場合、一番↑の libjpeg-devel 入れてるのと同じ要領で、
png 用のライブラリもあらかじめインストールしてください。
(そこは今回自分には必要なかったのではしょります)

詳しいことが知りたい方は、各コマンドを個別にぐぐってもらうと
それぞれ詳しい説明が書いたところに行き着ける・・・かもしれませんw

EFS を早速使ってみたらはまった

https://docs.aws.amazon.com/ja_jp/efs/latest/ug/whatisefs.html

EFSがやっと東京リージョンでも使えるようになった!
ということで、使ってみて、dd コマンドなんかで簡単にパフォーマンスを見たりして。
EBS よりちょっと遅いくらいかななんてことを簡単に確認した程度。

使い方は簡単なんだけど、特定のOSで、インスタンス再起動時にマウントされない、という症状が出た。

https://docs.aws.amazon.com/ja_jp/efs/latest/ug/whatisefs.html

結果的に「特定のOS」というよりは、/etc/fstab に無効なマウント設定があったのが理由だった。

Jul 30 18:48:06 stg-corp-site-1a systemd: Timed out waiting for device dev-xvdb.device.

みたいなログがあったら疑ってみてください。無効なマウント設定をはずしたら無事再起動時にもマウントされるようになった。

net.ipv4.tcp_timestamps

おおはまりしたので、記録。

あるシステムでのトラブル。サーバはよそのところ。こっちはクライアント。まったく同一の OS、同一の設定なのに、ホストによってあちらのサーバにアクセスできたりできなかったりする。以前から動いていたホストは問題ない。後から追加したホストがダメ。

http://ya.maya.st/d/200804c.html#s20080430_2

これに近似した状況。

web サーバにエラーログだけは出る。

[Mon Jun 11 12:34:08.181627 2018] [proxy:error] [pid 1380] (70007)The timeout specified has expired: AH00957: HTTP: attempt to connect to xx.xx.xx.xx:80 (xx.xx.jp) failed

で、先方に問い合わせてもアクセスの形跡が無いと言われてしまう。
真面目に調べてくれてないだけという可能性もあるけど、そういわれてしまうと証明しないとならない。


2台構成のサービスで、タイムアウトは片方のサーバでしか発生しない。
まずやったことは1台構成に縮退してみる。
結果:1台だとうまいこと動く。


web サーバの設定差を疑ったが、この時点でその線は消えた。

次に、NAT 経由でのアクセスであるため、NAT が怪しいと思い、NAT を交換。
結果:だめ


それでも NAT しかないやろと思い、NAT を1インスタンス1台という、
専用構成にしてみる。インスタンス毎にサブネットを別々にしていたのが幸いし、
これはルートテーブルを差し替えるだけで簡単に試せる。
結果:OK


いやいやそんなことあります?未曾有の経験。つまり NAT も NAT として
機能している。


次にやったことが、タイムアウトするまでの間に netstat してみる。

[ ~]$ netstat -n -t | grep xx.xx.xx.xx
tcp        0      1 xx.xx.xx.xx:52136           xx.xx.xx.xx:80           SYN_SENT    

ん?SYN_SENT でとまってる・・・。
つまり、TCP のハンドシェイクの時点で待ちになっちゃっているということ。
もし先方までアクセスが到達していたとしても、これじゃアクセスログは残らない・・・。

次。
どこまでアクセスは到達してるのか。

sudo tcpdump host xxx.xxx.xxx.xxx -w nat &
sudo tcpdump host xxx.xxx.xxx.xxx -w 1a &
sudo tcpdump host xxx.xxx.xxx.xxx -w 1c &

tcpdump してみて、プロトコルアナライザで見てみる。
ちなみに、Wireshark を使いました。
結果:
NAT まで到達して、先方までちゃんとアクセスを投げている!

しかし、TCP の SYN を送った後、先方から ACK が返ってこず、
数回リトライしてタイムアウトしている!


・・・この時点で、グーグルさんに登場願う。
「nat syn timeout」みたいな適当なキーワードでぐぐると、
出てくる出てくる、類似事例が。


一番まとまっているように見えたのが上記の方のページ。
先方の設定を変えてもらうことは出来ないので、各インスタンスに、

sysctl -w net.ipv4.tcp_timestamps=0
cat << 'EOS' > /etc/sysctl.d/tcp_timestamp.conf
net.ipv4.tcp_timestamps = 0
EOS

って感じで設定。


あっさりと問題は解決した。
この感謝の気持ちを込めて、キーワード入りのブログを残す。
お役に立てば幸いです。


その他にも実際にはいろいろ調べたけれども、結局 OS 依存するところが多いため、
あまり参考にならないと思われるので、割愛。

Java で stackTrace を String で受け取る方法

String stackTrace 
  = Arrays.asList(e.getStackTrace()).stream().collect(Collectors.toStringJoiner(“\n”)));

Java8 だと上記のような感じになると思います。もっとシンプルな方法はないものかね。
「いつこんなの使うの?」という疑問があると思いますが、「例外が起きた時メールで stacktrace 送ってくれ」って言われた時ですw

suid が利かなくてはまった

perl スクリプトの中で secure ログを cat するような処理を書いていて、secure ログを cat するには root 権限が必要なので、
その perl スクリプトを suid すればいいよね、と軽く考えていた。
suid はほぼ使う機会が無いので知らなかったのだけど、実はスクリプト系のものには suid は無効らしい。

perl やら ruby やら sh やらのスクリプトは、chmod u+s しても効果がない。バイナリな実行ファイルでないと、OS は setuid/gid フラグを無視してしまって意図した権限で実行してくれない。それを許すと 穴になるからしかたないというのは承知してるけどさ、どーしてもやりたいこともあるわけで、そのたびごとに C のラッパーを書くのはめんどくさい。仕事だからやるけどさ

http://ya.maya.st/d/200908a.html

で、suid で変更したidは起動したプロセスでのみ有効で、内部で別プロセスを生成するときには変更前のidが使われる、と同僚が教えてくれたので、これも初耳。以下、ちょっと検証として、あってるのかあってないのか、微妙なコード。

#include <unistd.h>
#include <pwd.h>
#include <stdio.h>

void main (char* args) {
        struct passwd* pw;
        pw=getpwuid(geteuid());
        printf("%s\n",pw->pw_name);
        system("id");
}
$ gcc a.c;sudo chown root:root a.out; sudo chmod u+s a.out;./a.out
root
uid=501(kamei) gid=501(kamei) groups=501(kamei),10(wheel)

「system("id");」のとこは、合ってるのかどうか自信ない。

ちなみに、perl では、昔は suidperl ってのをインストールすると、suid を使えたようだが、今はたぶん使えなさそう。
あんまりこれをまじめに調べるモチベーションが無いので、すみません、適当にぐぐった結果ですmm

MySQL 上のログテーブルの扱い方

保存期限を3か月とか、任意の期間で自動削除する仕組みについて。
ログっていうのは、アクセスログとかアクティビティーログを想定している。
単純にログテーブルを作成してデータを入れていくのは簡単だけど、古いデータをどのタイミングで、どのように消すか、というのが問題。

ただこれ調べ始めていきなり結論っぽいものを発見してしまった。

Mobageを支える技術 ~ソーシャルゲームの舞台裏~ (WEB+DB PRESS plus)

Mobageを支える技術 ~ソーシャルゲームの舞台裏~ (WEB+DB PRESS plus)

P216 あたりから、Range パーティションしたテーブルとイベントスケジューラを組み合わせてローテートを行う方法。普通これを使うんだろうな・・・。

MySQLパーティションテーブルについてはこちらがわかりやすい。
高速処理化!MySQLのパーティショニング機能を使ってみよう | 東京上野のWeb制作会社LIG

↓とても詳しい。さすが DeNA のなかのひと。
ソーシャルゲームのためのMySQL入門 - Technology of DeNA

日次等のタイミングでイベントスケジューラを利用して

を行うだけ。

ただし、以下のような事で、IF [NOT] EXISTS は使えないので、ちょっと工夫は必要。

ADD PARTITION と DROP PARTITION は現在 IF [NOT] EXISTS をサポートしていません。パーティションや分割されたテーブルをリネームする事も不可能です。その代わりに、もしパーティションをリネームしたいのであれば、パーティションをドロップして再作成する必要があります。そしてもし分割済テーブルをリネームしたければ、全てのパーティションをドロップし、テーブルをリネームし、そしてドロップされたパーティションをもう一度追加する必要があります。

MySQL :: MySQL 5.6 リファレンスマニュアル :: 13.1.7 ALTER TABLE 構文


イベント処理については以下。
http://idocsq.net/page/160
http://dev.mysql.com/doc/refman/5.1-olh/ja/create-event.html

レプリケーション考えると面倒が起きそうなので、ウチではイベントスケジューラ使わずに、素直に cron に perl スクリプト仕込む感じでやることにしそう。