harry’s memorandum

おれおれメモ

ssh-copy-id: Bourne shell script text executable

ssh-copy-idは便利だね。何も考えたくなければこれでいいし。

$ ssh-copy-id myuser@example.com

中身はシェルスクリプトだったりする。

$ file /usr/bin/ssh-copy-id
/usr/bin/ssh-copy-id: Bourne shell script text executable

cat /usr/bin/ssh-copy-id すると中身は結構短い。

#!/bin/sh

# Shell script to install your id_rsa.pub on a remote machine
# Takes the remote machine name as an argument.
# Obviously, the remote machine must accept password authentication,
# or one of the other keys in your ssh-agent, for this to work.

ID_FILE="${HOME}/.ssh/id_rsa.pub"

if [ "-i" = "$1" ]; then
  shift
  # check if we have 2 parameters left, if so the first is the new ID file
  if [ -n "$2" ]; then
    if expr "$1" : ".*\.pub" ; then
      ID_FILE="$1"
    else
      ID_FILE="$1.pub"
    fi
    shift         # and this should leave $1 as the target name
  fi
else
  if [ x$SSH_AUTH_SOCK != x ] ; then
    GET_ID="$GET_ID ssh-add -L"
  fi
fi

if [ -z "`eval $GET_ID`" ] && [ -r "${ID_FILE}" ] ; then
  GET_ID="cat ${ID_FILE}"
fi

if [ -z "`eval $GET_ID`" ]; then
  echo "$0: ERROR: No identities found" >&2
  exit 1
fi

if [ "$#" -lt 1 ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
  echo "Usage: $0 [-i [identity_file]] [user@]machine" >&2
  exit 1
fi

{ eval "$GET_ID" ; } | ssh $1 "umask 077; test -d .ssh || mkdir .ssh ; cat >> .ssh/authorized_keys" || exit 1

cat <<EOF
Now try logging into the machine, with "ssh '$1'", and check in:

  .ssh/authorized_keys

to make sure we haven't added extra keys that you weren't expecting.

EOF


shは便利なんだけど、こういう書き方をしないとNULLSTRINGのチェックができないのは未だになれない。10年たってもなれない。

  if [ x$SSH_AUTH_SOCK != x ] ; then


いつも authorized_keys のタイプ間違えそうになるので ssh-copy-idとても便利です。ssh-copy-idはたいへん便利です。

base64の備忘録

とりあえず、base64をしたかったのですが、調べると色々な方法があるなぁ、と思ったので備忘録。

opensslコマンド

一番よく使う方法かな。

$ echo -n dharry | openssl enc -base64
ZGhhcnJ5
$ echo  "ZGhhcnJ5" | openssl  enc -d -base64; echo
dharry
base64コマンド

Linuxだとこれかな。coreutilsは便利だけど他のUNIXだとなかったりするんだな。

$ echo -n dharry | base64
ZGhhcnJ5
$ echo -n "ZGhhcnJ5" | base64 -d; echo
dharry
$ rpm -qf /usr/bin/base64
coreutils-5.97-34.el5_8.1
nkfコマンド

これはこれで便利

$ echo -n "dharry"| nkf  -MB; echo
ZGhhcnJ5
$ echo -n "ZGhhcnJ5"| nkf -mB; echo
dharry
perl

perlはどのUNIXでもあるから一番楽かも。でもHP-UX11.00ぐらいだと厳しい。

$ echo -n "dharry" | perl -MMIME::Base64 -0777 -ne 'print encode_base64($_)'
ZGhhcnJ5
$ echo -n "ZGhhcnJ5" | perl -MMIME::Base64 -ne 'print decode_base64($_)'; echo
dharry
ruby
$ echo -n dharry   | ruby -r base64 -e 'puts Base64.encode64(STDIN.read)'
ZGhhcnJ5
$ echo -n ZGhhcnJ5 | ruby -r base64 -e 'puts Base64.decode64(STDIN.read)'
dharry
python
$ echo -n dharry | python -c "import base64,sys; base64.encode(sys.stdin,sys.stdout)"
ZGhhcnJ5
$ echo -n ZGhhcnJ5 | python -c "import base64,sys; base64.decode(sys.stdin,sys.stdout)"
dharry
PowerShell

コマンドレットは便利と思ったけどいまだになじめない。慣れは重要ですね。

PS C:\Users\dharry> $str = "dharry"
PS C:\Users\dharry> $str =  [Convert]::ToBase64String([System.Text.Encoding]::GetEncoding("iso-2022-jp").GetBytes($str))
PS C:\Users\dharry> $str
ZGhhcnJ5
tcl

tclshで試してみた。centosのtclだとbase64ライブラリがなかったのでActiveStateのActiveTCL8.5.11.1で確認。

% package require base64
2.4.2
% base64::encode "dharry"
ZGhhcnJ5
curl

apachebasic認証に渡すときはbase64にしているのでwgetcurlでもいけるはずだ。でも少しawkで頑張れば行けると思うけど面倒だから使わない。

$ curl -vu dharry: http://example.com 2>&1 | awk '{ if($0 ~/Authorization/) print $(NF)}'
ZGhhcnJ5Og==
$ echo -n ":" | base64
Og==
vbs

なんだかvbsが嫌になってきた。

Private Function base64(str)
	Dim dom, elem, bin, result

	Set st = CreateObject("ADODB.Stream")
	With st
		.Type = 2
		.Charset = "Shift-JIS"
		.Open
		.WriteText str
		.Position = 0
		.Type = 1
		bin = st.Read
		.Close
	End With

	Set dom = CreateObject("Microsoft.XMLDOM")
	Set elem = dom.CreateElement("tmp")
	elem.DataType = "bin.base64"
	elem.NodeTypedValue = bin
	result = elem.Text

	base64 = result
End Function
Wscript.echo base64("dharry")

単語を数える例のやつ

wordcountの例題は map/reduce でよくでてくるよね。

ruby

rubyは便利。

array = %w(foo bar hoge foo foo bar fuga hoge)

h = Hash.new(0)
array.each {|e| h[e]+=1}
p h
 #=> {"fuga"=>1, "foo"=>3, "hoge"=>2, "bar"=>2}

perl

perlも便利。初期化しなくてもいいのかしら。

use Data::Dumper;

my @array = qw(foo bar hoge foo foo bar fuga hoge);
my %h = {};

foreach my $e (@array) {
  $h{$e}++;
}

print Dumper(\%h);

 #=>
  #$VAR1 = {
  #          'bar' => 2,
  #          'fuga' => 1,
  #          'foo' => 3,
  #          'hoge' => 2,
  #          'HASH(0x12af940)' => undef
  #        };

bash4

bash の version 4 からは連想配列が使える。知らない間に機能アップしている。

array=(foo bar hoge foo foo bar fuga hoge)
declare -A h # 連想配列hを宣言

for e in ${array[@]}; do
  h[$e]=$(( h[$e] + 1 ))
done

# ${h[*]}はvalues, ${!h[*]}はkeys
for e in ${!h[*]}; do
  echo "$e => ${h[$e]}"
done

 #=>
  #fuga => 1
  #bar => 2
  #foo => 3
  #hoge => 2

bash3

CentOS5/RHEL5だとbash version 3 だから連想配列は使えない。どうしようかと思ったけど意外とシンプルにかけました。連想配列が使えるawkで書けばいいというオチもありますね。

vardir=/dev/shm/var.$$
array=(foo bar hoge foo foo bar fuga hoge)

[ ! -d $vardir ] && mkdir -p $vardir
for e in ${array[@]}; do
  echo -n 1 >> $vardir/$e
done

cd $vardir
ls -l * | awk '{ print $5, "=>", $NF}'
\rm -fr $vardir

 #=>
  #bar => 2
  #foo => 3
  #fuga => 1
  #hoge => 2

awk

awkはこんな感じかな。間違っていたらごめんなさい。

array=(foo bar hoge foo foo bar fuga hoge)

echo ${array[*]} |awk \
'{
  for(i=1;NF>=i;i++)
    h[$i]++i
}
END {
  for(k in h)
    print k, "=>" h[k]
}'

#=>
 #fuga =>1
 #hoge =>2
 #bar =>2
 #foo =>3

シェルスクリプトをコンパイルできるshcで遊んでみた

使うことはないかもしれない。でも面白いです。

shcをインストール

 $ sudo apt-get install shc

なかったらソースをダウンロードしてコンパイルしてください。

 $ wget http://www.datsi.fi.upm.es/~frosal/sources/shc-3.8.7.tgz
 $ tar xvzf shc-3.8.7.tgz
 $ cd shc-3.8.7/
 $ make

shcでコンパイル

テストで /usr/bin/ldd を使用。 なんで lddってshell script ってイメージがないんだろう。

$ file /usr/bin/ldd
/usr/bin/ldd: Bourne-Again shell script text executable
$ cp -p /usr/bin/ldd .
$ ./shc  -v -r -T -f ./ldd
shc shll=bash
shc [-i]=-c
shc [-x]=exec '%s' "$@"
shc [-l]=
shc opts=
shc: cc  ./ldd.x.c -o ./ldd.x
shc: strip ./ldd.x
shc: chmod go-r ./ldd.x
$ file ./ldd.x
./ldd.x: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, stripped
$ ./ldd.x /bin/ls
        linux-vdso.so.1 =>  (0x00007fff0d9ff000)
        libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007f2ed8878000)
        librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f2ed8670000)
        libacl.so.1 => /lib/x86_64-linux-gnu/libacl.so.1 (0x00007f2ed8467000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f2ed80d3000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f2ed7ecf000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f2ed8a9f000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f2ed7cb0000)
        libattr.so.1 => /lib/x86_64-linux-gnu/libattr.so.1 (0x00007f2ed7aab000)

foo.x.c というCのソースができるので、中身を眺めてみるのもオツなものです。

仕事がダラけてしまったのでシェルスクリプトでプログレスバーやってみた

やっぱ、プログレスバーがないと動いているのか分からなくてイラっとくるよね。というので、シェルスクリプトプログレスバーを簡単にできないかな、と思い書いてみた。

progress() {
  _bar=$1; _bar=${_bar:=.}
  while :
  do
    jobs %1 > /dev/null 2>&1
    [ $? = 0 ] || break
    echo -n ${_bar}
    sleep 0.1
  done;
}

usage() {
  echo "usage:$0 [command]"; exit;
}

[ $# = 0 ] && usage

"$@" &
progress

上記コードをprogress.shとして、こんな感じで時間がかかりそうな処理のコマンドを引数に渡してあげればOK.

./progress.sh sleep 10
..............................................................................................

barコマンド

しかし、探せばこんなごみコード書かなくても便利なものがあったりもする。このbarコマンドはcatのプログレスバー付きコマンドという感じです。これ、すげー便利じゃないですか。最初からこれにすればよかった。
http://www.theiling.de/projects/bar.html

まずはテストゴミファイル
dd if=/dev/urandom of=hoge.img bs=1M count=10
圧縮してバックアップ。
./bar -n  hoge.img | gzip -1 > hoge.img.gz
 91% [==============================================================......]
圧縮ファイルの展開。
./bar -n hoge.img.gz | gzip -d -c  > hoge-new.img
 85% [==========================================================..........]
ファイルのコピー。

でもこの -o オプションは 「 -o FILE (Redirects output to a file.)」 とアウトプットするファイルを指定するので、通常のcpとは順番が逆になる。 「cp source dest」 ではなく 「bar -o dest source」 間違えやすいのに間違えるとコピー元ファイルは0バイトになってしまう漢らしいシンタックスだ。

./bar-1.4$ ./bar -o dst src
 60% [=========================================...........................]

潔し、っていうコマンドはいいですね。身が引き締まります。

Bashの変数パラメータ展開はやっぱし便利

パターン照合演算子ってやつは便利だなーとしみじみ思ったので。

バイト数だしたり

$ x="/usr/share/apt/ubuntu-archive.gpg"
$ echo ${#x}
33

切り出したり (${parameter:offset:length})

$ x="/usr/share/apt/ubuntu-archive.gpg"
$ echo ${x:1:3} ${x:5:5} ${x:11:3} ${x:15:18}
usr share apt ubuntu-archive.gpg

置換したりできる。

x="sumomo mo momo mo momo no uchi"
$ echo $x
sumomo mo momo mo momo no uchi
$ echo ${x//momo/}
su mo mo no uchi
$ echo ${x//momo/banana}
subanana mo banana mo banana no uchi

basenameやdirnameコマンドぽいこともできる。

_basename() {
  local path=$1
  echo ${path##*/};
}

_dirname() {
  local path=$1
  echo ${path%/*};
}

_basename2() {
  local path=$1
  echo `_basename ${path%.*}`;
}

_extname() {
  local path=$1
  echo ${path##*.};
}

usage() {
  >&2 echo usage: $0 [path]
  exit 1;
}

[ $# -ne 1 ] && usage

for func in  _basename _dirname _basename2 _extname
do
  echo "${func}(): `eval $func $1`"
done

結果はこんなかんじ。

$ ./test.sh  /usr/share/apt/ubuntu-archive.gpg
_basename(): ubuntu-archive.gpg
_dirname(): /usr/share/apt
_basename2(): ubuntu-archive
_extname(): gpg

シェルの乱数の覚書

いろいろあるんだな、って思った。

$ echo $$
25653
$ awk 'BEGIN { print PROCINFO["pid"] }'
26712
$ echo `date +%s`
1290451043
$ echo $RANDOM
28006
$ awk 'BEGIN{ srand(); print rand() }'
0.384664
$ awk 'BEGIN { srand(systime() + PROCINFO["pid"]); print rand() }'
0.270381
$ od -vAn -N4 -tu4 < /dev/urandom
  177439376
$ od -An -N2 -i /dev/random
       25895
$ dd if=/dev/urandom count=1 2> /dev/null | cksum | cut -f1 -d" "
655519971