2014-12-28

Zsh: 擬似ポインタを使った関数の制作

これまでは簡単な関数しか作っていなかったので、結果を戻すには;
  1. 結果をechoで表示して終わる、
  2. 結果をグローバル変数に書き込む、
従って「 インタラクティブな処理(echo read)を必要とした時」には、 2.の方法しか使えないので、手間が掛かる。

そこで「 "From Bash to Z shell", O. Kiddle et.al., ISBN13:978-1-59059-379-9」を探ってみると、「Chapter 12, Variable Indirection, pp305..306」に「function double」の解説があったので試してみた;
#!/bin/zsh
double()
{
 #local i=${!1}  # Bash style didn’t work
 local i=${(P)1} # Zsh style works well.
 (( i=i*2 ))
 eval "$1='$i'"
}

echo ---- test of double ---------------
num=$((3))
echo "\$num=$num before call of 'double'"
echo -----------------------------------
set -x
double num
set +x
echo -----------------------------------
echo "\$num=$num after call of 'double'"
echo -----------------------------------

 その動作結果;
u1@MmM11[~/myZsh]% double
---- test of double ---------------
$num=3 before call of 'double'
-----------------------------------
+/Users/u1/myZsh/double:18> double num
+double:3> local 'i=3'
+double:4> (( i=i*2 ))
+double:5> eval 'num='\''6'\'
+(eval):1> num=6
+/Users/u1/myZsh/double:19> set +x
-----------------------------------
$num=6 after call of 'double'
-----------------------------------
u1@MmM11[~/myZsh]%


Googleで関連を調べると、少数ながら有用なサイトが見つかった;
  • Bash and Zsh pointer 
    • http://yogsototh.wordpress.com/2008/07/03/bash-or-zsh-pointer/
  •  Double and triple substitution in bash and zsh
    • http://unix.stackexchange.com/questions/68042/double-and-triple-substitution-in-bash-and-zsh
      • answered Mar 24 '13 at 3:24 by Gilles
  •  How to return a string value from a bash function 
    •  http://stackoverflow.com/questions/3236871/how-to-return-a-string-value-from-a-bash-function
      • answered Jul 14 '10 at 2:39 by bstpierre
これらの3つの記事を参考にして、私はトライ&エラーをしました。その結果、関数の動作を解釈出来たので紹介します。
#!/bin/zsh
double_2()        # General template for pointer like function.
{
 local p=$1       # Set a pointer,p as the address,num in $1; 
                       # like 「p=&num」 in C language.
 local i=${(P)p}  # Read the pointing value,*p & Set to a variable,i; 
                       # like 「i=*p」 in C language.
 #(( i=i*2 ))     # It works well. But, 
 i=$((i*2))       # I prefer the left form rather than the above form.
 eval "$p='$i'"   # Write new value,i to the pointing value *p.
                       # like 「*p=i」 in C language.
                  # '$i': single quotes are necessary
                       # for the variable including spaces.
}

echo ---- test of double_2 -------------

num=$((4))
echo "\$num=$num before call of 'double_2'"
echo -----------------------------------
set -x
double_2 num
set +x
echo -----------------------------------
echo "\$num=$num after call of 'double_2'"
echo ------------------------------------

 
 その動作結果;
u1@MmM11[~/myZsh]% double_2                             23:10:40
---- test of double_2 -------------
$num=4 before call of 'double_2'
-----------------------------------
+/Users/u1/myZsh/double_2:27> double_2 num
+double_2:2> local 'p=num'
+double_2:4> local 'i=4'
+double_2:7> i=8
+double_2:8> eval 'num='\''8'\'
+(eval):1> num=8
+/Users/u1/myZsh/double_2:28> set +x
-----------------------------------
$num=8 after call of 'double_2'
------------------------------------
u1@MmM11[~/myZsh]%                                             23:10:34

今回の環境をTerminalで確認した;

u1@MmM11[~]% zsh --version                                       11:03:16
zsh 5.0.2 (x86_64-apple-darwin13.0)
u1@MmM11[~]% sw_vers                                             11:03:20
ProductName:Mac OS X
ProductVersion:10.9.5
BuildVersion:13F34
u1@MmM11[~]%                                                     11:03:25


このページの履歴
  1. 開始 2014-12-28(日) 23:18:01 
  2. 追加 2014-12-29(月) 13:51:58 「Terminalで確認 」を直接htmlで放り込んだ。スペースの調節が難しい。

2014-12-15

引用タグ表示の問題点

インターネットの閲覧には、「OS X Mavericks 10.9.5」上で、「Fire 34.0.5」と「Safari 7.1.2」とを使っている。他方、「Google Chrome 39.0.2171.95」での「日本語 → 英語:翻訳機能」を用いて英語表現を確認している。これまでは特に問題はなかった。
「日本語 → 英語:翻訳機能」を設定している。
しかし、引用タグ(blockquote tag)に長めのテキストを入れるようになったところ、日本語表示では問題が無くても、英語表示になると「表示が詰まる」事が起こるのに気がついた。サンプルを下に示します。
 (1) Scalar variable: $s.
   • by command: s='1 2 3'
   scalar: $s=»1 2 3«
   scalar:${#s}=5

(2) Array variable: $a.
   • by command: a='(4 5 6)'
    array: $a=»4 5 6«
    array:${#a}=3

(3) convert scalar:$s to array:$b.
   • by command:  echo $s | read -A b
    array: ${b}=»1 2 3«
    array:${#b}=3

(4) copy array:$a to array:$c.
   • by command:  echo "$a" | read -A c
    array: ${c}=»4 5 6«
    array:${#b}=3
参考に、英語への翻訳モードでのChrome表示のスクリーン・ショットを御覧ください;

私はブロガーの保守をサボっていたので、迷うばかりだ。フォーラムを探して、お伺いを立てるしか無いかなぁ。

SyntaxHighlighter


その後、トライ&エラーをしているうちに、SyntaxHighlighter表示ですら「Chromeの英訳モード」で「奇妙な振る舞い:不要なスペースが追加される」ことが判ったのでサンプルを示します;
!/bin/zsh 
a=($(ls))
i=0
for et in $a; do
    i=$(($i+1))
    echo "$i $et"
done

そのスクリーン・ショットも表示しておきます;








 

自動翻訳だけでも大変なものだが、自動表示も意外と難しいのだろうな。

バーベイタムの表示


昔のwikiでのpre-tagの設定を使ってみました。

pre class="verbatim-hard"

pre.verbatim-hard {
    background-color: #faf0fa;
    border: solid 1px #66f; 
    padding: 1em 1em 1em 1em;
    margin-left: 3em;
    margin-right: 0em;
    line-height: 120%;
}

/Users/u1/myZsh/func_pointer:43> fn ipv
+fn:3> ptr0=ipv 
+fn:4> data0=+fn:4> echo 'd c b a'

+fn:4> data0='d c b a' 
+fn:10> data1='W X Y Z' 
+fn:15> eval 'ipv='\''W X Y Z'\'
+(eval):1> ipv='W X Y Z' 


Screen Shot of above "verbatim-hard"

これを観察すると、不良箇所は系統的に発生している;
  • 不要な空白が挿入される場合;
    • /Users/ → / Users /
  • 逆に、必要な空白が引き抜かれる場合:最終行を例に取ると;
    • ipv='W X Y Z' →ipv = 'WXYZ'
  • 小文字で始まる単語が大文字に変換される場合:
    • +(eval):1> → + (Eval) : 1>
 これらを修正してもらえれば、有難いなぁ。
    # 素人判断では、blockquoteの改良より、こちらのpreの改良が楽では?

___
このページの履歴
  1. 開始 2014-12-15(月) 18:03:41
  2. 追加 2014-12-16(火) 16:20:39  SyntaxHighlighter表示
  3. 追加 2014-12-16(火) 20:26:03  pre.verbatim-hard

2014-12-13

zsh: 配列変数の操作方法

前回の報告、Zsh:「スカラー変数と配列変数の初歩的な処理法」を書いた後で、いくつかの小技を知ったので纏めてみました。


(1) スカラー変数からアレイ変数への変換



「"From Bash to Z Shell", Oliver Kiddle et.al. , Constructing an Array, p281」を眺めていたら;
  • src_files=( **/*.[ch]  )
という記述があった。そこで、簡単な実例を作ってみた;
#!/bin/zsh 
a=($(ls))
i=0
for et in $a; do
    i=$(($i+1))
    echo "$i $et"
done
この変数aは配列変数で在ることが確かめられた。要は標準出力を持つコマンド(ls)を「$()」の中で実行; $(ls)すれば配列変数に変換できる。

そこでスカラー変数,sを表示するコマンド「echo s」について同じことをすると、配列変数,aに無事に変換できました、前回の手法と比較すると直截な表現だと思います。
  • a=( $(echo $s) )        #今回
  • echo s | read -A a     #前回

(2)  アレイ変数の操作


元ネタは「Zsh文法帳なのですー>ω<というサイトです。
この中に、興味深いのが2つありました;
  • 「配列を別の配列変数に代入するときは、()で囲むのです」
    • b=($a)             #配列から配列へのcopy
  • 「要素の追加には+=を」
    • a+=(x y)           #配列へのappend
これらのテスト中に偶然出来たのですが、要素の追加法です;
  • a=(u v w $a x y z)    #append
zshのマニュアルは難しけど、トライ&エラーで思わぬ動作を見つけるのも面白いかな。



関連記事



____
このページの履歴
  1. 開始 2014-12-13(土) 17:49:43 
  2. 修正 2015-06-15(月) 19:22:59  e → a 
  3. 追加 2015-06-15(月) 21:30:08  関連記事 
  4. 修正 2015-06-17(水) 11:14:13  「a=( $(echo s) )  」→「a=( $(echo $s) )   」

2014-12-08

Zsh:「スカラー変数と配列変数の初歩的な処理法」

これまで「os x」でBashスクリプトを使ってきました。最近、中規模のスクリプトを各必要が出てきたので、Zshを使うようになってきた。
初心者にとってZshの特徴は;
  • 強力なprintコマンド群(echo, print, printf)。
  • 配列変数の記法がスマート。 
  • 高速な処理速度。
  • 結果が見やすい:ボールド体や色付き文字の出力。
でも、初心者には「具体的な例題」が手に入れにくいという欠点がある。もちろん上級者のようにマニュアルをよく理解すれば、好き勝手な設定を構築することもできるらしい。

他方、初心者でも配列変数を使い込んで来るに連れて、次のような作業がしたくなる;
  • 「スカラー変数: scalar variable」から「配列変数: array variable」への変換: 
    • 下記(3)参照。
      • 「echo $scalar | read -A array1」
  • 「配列変数: array variable」から「配列変数: array variable」へのコピー:
    • 下記(4)参照。
      • 「echo $array1 | read -A array2」
  •  ファンクションの「引数:arguments」に「配列変数:array variable」を渡したくなる:
    • 下記(5a,b)参照。
      • 関数読み出し:「function "$array1"」
      • 関数内部処理:「echo "$1" | read -A array3」


トライ&エラーの結果、「read -A」というコマンドを利用すると、上記の課題が容易に実行できることが判ったので、下記に【A】結果と【B】スクリプトを示します。

【A】スクリプトの動作結果  


以下の表示でブロックコート(blockquote)を細切れにしたのは、"Google Chrome"で"translate from Japanese to English"を設定すると、表示が乱れるのを防止する為です。

u1@MmM11[~]% t.arr4a            11:36:14
(1) Scalar variable: $s.
   • by command: s='1 2 3'
   scalar: $s=»1 2 3«
   scalar:${#s}=5
(2) Array variable: $a.
   • by command: a='(4 5 6)'
    array: $a=»4 5 6«
    array:${#a}=3
(3) convert scalar:$s to array:$b.
   • by command:  echo $s | read -A b
    array: ${b}=»1 2 3«
    array:${#b}=3
(4) copy array:$a to array:$c.
   • by command:  echo "$a" | read -A c
    array: ${c}=»4 5 6«
    array:${#b}=3
(5a) test of function call.
    • give array variavle,"$a"to the function;
    • by command: test_of_array_input "$a"
  Function $0 begin ------------------
   test_of_array_input: $1=4 5 6
   (5b) convert scalar:$i to array:$d
     by command:  echo "$i" | read -A d
       array: ${d}=»4 5 6«
       array:${#d}=3
  Function $0 stop ------------------
(6) print each element of arrays by for-loop on $a,$b,$c, and $d.
             (2)      (3)     (4)      (5b)
     $j     $a[$j]   $b[$j]  $c[$j]   $d[$j]
    ----    ------   ------  ------   ------
      1       4        1       4        4
      2       5        2       5        5
      3       6        3       6        6
(7) copy array:$a to scalar:$t.
  by command:  t=$a
    scalar: ${t}=»4 5 6«
    scalar:${#t}=5
u1@MmM11[~]%    

【B】スクリプト本体 

#!/bin/zsh 

# t.arr4a:

# 2014-12-08 by iritani/mNeji

test_of_array_input()
{
# input as scalar $1
local i=$1
 echo '  Function $0 begin ------------------'
 echo "   $0: \$1=$1"
 echo "$1" | read -A d
 echo '   (5b) convert scalar:$i to array:$d'
 echo '     by command:  echo "$i" | read -A d'
 echo '       array: ${d}='»${d}«
 echo '       array:${#d}='${#d}
 echo '  Function $0 stop ------------------'
}

#---------------- main ------------------------

echo '(1) Scalar variable: $s.'
echo "   • by command: s='1 2 3'" # scalar
s='1 2 3'
echo '   scalar: $s='»${s}« 
echo '   scalar:${#s}='${#s}
echo

echo '(2) Array variable: $a.'
echo "   • by command: a='(4 5 6)'" # array
a=(4 5 6) 
echo '    array: $a='»${a}«
echo '    array:${#a}='${#a}
echo

echo '(3) convert scalar:$s to array:$b.'
echo '   • by command:  echo $s | read -A b'
echo $s | read -A b
echo '    array: ${b}='»${b}« 
echo '    array:${#b}='${#b}
echo

echo '(4) copy array:$a to array:$c.'
echo '   • by command:  echo "$a" | read -A c'
echo $a | read -A c
echo '    array: ${c}='»${c}«
echo '    array:${#b}='${#c}
echo

echo '(5a) test of function call.'
echo '    • give array variavle,"$a"to the function;'
echo '    • by command: test_of_array_input "$a"'
test_of_array_input "$a" 
 # double-quote necessary for "$a" as function's argument $1
 # $a --> the first element only as all arguments passed
echo

echo '(6) print each element of arrays by for-loop on $a,$b,$c, and $d.'
    echo '             (2)      (3)     (4)      (5b)'
    echo '     $j     $a[$j]   $b[$j]  $c[$j]   $d[$j]' 
    echo '    ----    ------   ------  ------   ------'
for j in {1..3}; do
 echo "      $j       $a[$j]        $b[$j]       $c[$j]        $d[$j]"
done
echo

echo '(7) copy array:$a to scalar:$t.'
echo '  by command:  t=$a'
t=$a
echo '    scalar: ${t}='»${t}«
echo '    scalar:${#t}='${#t}
echo

# end of script

【感想】
配列変数を引数にする方法は系統的に改良してもらいた。当面は、文句を言う前にスキルの向上が先でしょうね。
素人には、「array4=( $scalar4 )」 といった直感的な記述が使えないのが不思議です。

____
このページの履歴
  1. 開始 2014-12-08(月) 21:51:06 
  2. 追加 2014-12-09(火) 11:09:11  【感想】「array4=( $scalar4 )」
  3. 修正 2014-12-15(月) 14:51:46  【A】スクリプトの動作結果  :Chrome対策

注目の投稿

Terminalでの、なんちゃってViモドキ

近頃、ようやくKarabiner-Elementsに慣れてきたので、 Terminalで動作する「擬似Vi-Mode」を作って見たので、ご紹介します。 『概要』 「擬似Vi-Mode」の所以は、方向キー「←↓↑→」を通常の「hjkl」ではなくて「jkil」としました。これ...