顯示具有 工作 標籤的文章。 顯示所有文章
顯示具有 工作 標籤的文章。 顯示所有文章

星期二, 6月 12, 2012

bash 如何用變數取得變數名稱

中文形容的不恰當,英文比較貼切
bash, how to get variable name from variable

假設bash有如下變數:
st21413=5234.3
st21416=4432.2
st52405=5732.1
所以
echo $st21413 會得到 5234.3
那如果
A=st21413
有沒有什麼方法可以透過A得到5234.3的值?
直覺得想法像是
echo $`$A`
結果得到 $st21413 而非 5234.3 …
正解:
A=st21413
echo ${!A}
即可得到5234.3
如果
B=${!A}
那 B 的值就是 5234.3 囉,即
echo $B 會得到 5234.3

星期一, 5月 14, 2012

用 ImageMagick 的 convert 合併圖檔

話說生論文的重點在於你有沒有好看的圖…英文不好、論點不佳、結果很慘,只好靠作圖來加分…是這樣嗎。
使用GMT繪圖時,撰寫的scripts習慣以一張圖為一個檔案,並且直接轉成jpg。 可是在論文編排時,常常需要把幾張圖合成一張,然後在圖中附上a,b,c,d。 以前的做法是用power point編排後再存成ps檔,再由ps檔轉成jpg(此時可設定解析度)。 本來以為這樣的做法,解析度可以保持(事實上解析度是很大…可以過論文排版的檢查),不過實際上圖的解析度並沒有很好。 另外的做法是用gimp處理jpg檔,或是保留ps檔使用coreldraw,可是對於不常用這些軟體的我來說很是麻煩。
由於我一直有在使用ImageMagick,尤其是要執行縮小或製作gif檔時使用convert命令的方法很是方便。 當然強大的ImageMagick如果只是要把很有規則(大小一樣有的沒的)的幾張圖重新排列,並加上(a)(b)(c)(d)應該不難,只是我不會,也一直沒空去了解。最近又要排版了,再用回power point實在品質太差(我標準提高了嗎?)。所以只好花點時間研究ImageMagick,哇~簡值是神奇,只要一個指令就可以搞定。 例如我有四張圖如下:




然後透過下面的指令:
convert \( -page -0-0 \( figure4-a.jpg -page +350+220 -background none -fill black -pointsize 220 label:\(a\) -flatten \) -page -0-0 \( figure4-b.jpg -page +350+220 -background none -fill black -pointsize 220 label:\(b\) -flatten \) -bordercolor black -border 50 +append \) \( -page -0-0 \( figure4-c.jpg -page +350+220 -background none -fill black -pointsize 220 label:\(c\) -flatten \) -page -0-0 \( figure4-d.jpg -page +350+220 -background none -fill black -pointsize 220 label:\(d\) -flatten \) -bordercolor black -border 50 +append \) -append out.jpg
就變成這樣一張圖:

很神奇對不對(我是指我能寫出這天書般的指令),只是上面的指令記不起來的啦,下次也保證看不懂的啦。既然已經花點時間去了解ImageMagick裏convert的用法,也相信下次要用時會忘記,只好寫個簡單的scripts幫助記憶,並且希望可以再下次要用時直接取用。如果你有需要就請隨便用,把你的圖搞壞了別怪我就是了。
convert 可以透過( ) 來優先處理,所以下面的邏輯是先對每一張圖加上(a) (b) (c) (d),用-label給文字,-pointsize給大小,-page給位置。另外,圖要合併時是沒間距的,所以透過-border加個白色外框(由-bordercolor設定白色)。
然後用+append把二張做橫向合併,所以每個橫向的合併要再用一個( )
最後把橫向合份好的結果再用-append用垂向合併。大致上是這個意思
convert   ( (圖1加字) (圖2加字) +append)  ( (圖3加字) (圖4加字) +append ) )  -append  outfigname.jpg

scripts的寫法是當然由最裏面的小圖一路往上拓展,內容如下:

figncols=2
fignrows=2
outfigname=out.jpg
figname[1]=figure4-a.jpg
figname[2]=figure4-b.jpg
figname[3]=figure4-c.jpg
figname[4]=figure4-d.jpg

labelvar[1]="label:\(a\)"
labelvar[2]="label:\(b\)"
labelvar[3]="label:\(c\)"
labelvar[4]="label:\(d\)"
labelvar[5]="label:\(e\)"
labelvar[6]="label:\(f\)"
labelvar[7]="label:\(g\)"
labelvar[8]="label:\(h\)"
labelvar[9]="label:\(i\)"
labelvar[10]="label:\(j\)"
labelvar[11]="label:\(k\)"
labelvar[12]="label:\(l\)"
# ( if rows=3, cols=4, there will have 12 figs)
#          rows
# c    fig1   fig2   fig3
# o    fig4   fig5   fig6
# l    fig7   fig8   fig9
# s    fig10  fig11  fig12
#
#
figtots=`expr $figncols \* $fignrows`
pagevar="-page +350+220"  # label position in pixel
#  下面設定圖與圖中的間隔及顏色,這裏是設黑色,寬度50
bordervar="-bordercolor black -border 50"
pointsize="-pointsize 220"  # font size in pixel
pointvar="$pagevar -background none -fill black $pointsize"
for (( i=1; i<=$figtots; i++ )); do
  a[$i]=`echo " -page -0-0 \( ${figname[$i]} $pointvar ${labelvar[$i]} -flatten \)"`
done
for (( i=1; i<=$fignrows; i++ )); do
    b[$i]=`echo "\("`
  for (( j=1; j<=$figncols; j++ )); do
    k=`expr \( $i \- 1 \) \* $figncols \+ $j `
    b[$i]=`echo "${b[$i]} ${a[$k]}"`
  done
    b[$i]=`echo "${b[$i]} $bordervar +append \)"`
done
c=`echo "convert "`
for (( i=1; i<=$fignrows; i++ )); do
  c=`echo "$c ${b[$i]}"`
done
c=`echo "$c -append $outfigname"`
echo $c
echo "the command above is excuting"
eval $c
echo "done"

星期三, 7月 13, 2011

/etc/sysconfig/iptables 被重設

最近某一台新機器的iptables改完之後常常會跑回原先的設定
仔細看一下/etc/sysconfig/iptables 的檔案,發現前二行是
# Firewall configuration written by system-config-securitylevel
# Manual customization of this file is not recommended.
大意是說,這個iptables是由 system-config-sercuritylevel 產生,查了一下
發現這是一個執行檔在/usr/bin下
改為root,執行system-config-sercuritylevel (文字介面即可)
嗯,是一個防火牆的設定介面…裏面的設定值大概固定時間會寫一次到iptables這個檔案,難怪怎麼設定都沒用。
怎麼解決?就把要開的埠在寫在自訂就好了5901,5902,5903 餘類推。

POM bcond

純個人紀錄用…
最近在計算海嘯的例子發現在邊界上有明顯的反射…

這個試了n天,這應該是預設邊界條件的ramp(一個介於1~0間的值)所致…
ramp的目的是要由邊界推動模式時,可以在一個時間內慢慢的起動,免得一下推太用力爆掉,但是這個算例(海嘯)是由計算區域內往外傳,所以ramp反而把該往外傳的值變的比較小…導致出去的不乾淨,造成反射。下面是原始的code,在bcond 的subroutine中(idx=2)。
       vaf(i,jm)=vabn(i)
     $          +rfn*sqrt(grav/h(i,jmm1))
     $          *(el(i,jmm1)-eln(i))
       vaf(i,jm)=ramp*vaf(i,jm)
下述的code應該有一個邏輯上的錯誤,就是不應該全部的值乘上ramp,而是只有邊界往內傳的部份要乘上ramp。照上面的想法,只要不要啟動ramp(即ramp一直為1)就應該不會有反射(或至少要變的比較小),試跑之後,得到下面的結果:
果然邊界的反射沒有了…
按上面的敘述把code改成如下(共四個邊界,這舉一隅,餘類推):
       vaf(i,jm)=ramp*vabn(i)
     $               +rfn*sqrt(grav/h(i,jmm1))
     $               *(el(i,jmm1)-ramp*eln(i))
這一行就不要了,看是刪掉還是註解掉。
c       vaf(i,jm)=ramp*vaf(i,jm)
註:話說回來rfn 放的地方也怪怪的…印像中,他是rfe=0或1,第於1就沒什麼意思,有乘等於沒乘。等於0就讓vaf=0,就等於設了一道牆,既然設為牆了,vabn(i)應該也要乘才是。不過目前為止,我的例子的rfn都是1,就暫且不管了。不過還是把認為對的寫在下面,當成記錄,方便哪天用到時可以查。
       vaf(i,jm)=ramp*vabn(i)
     $              +sqrt(grav/h(i,jmm1))
     $              *(el(i,jmm1)-ramp*eln(i))
       vaf(i,jm)=rfn*vabn(i)

星期三, 6月 01, 2011

intel fortran 使用大的陣列 ( > 2G)

跑數值的當然會需要有大大的記體,然後開大大的陣列
編譯時如果遇到  relocation truncated to fit 錯誤,那編譯時就加入
-shared-intel -mcmodel=medium
例如:
ifort -shared-intel -mcmodel=medium mycode.f90


如果用的是動態陣列,不會先知道用多大的陣列,可以編譯過關
但是執行時可能會遇到 segment fault 錯誤
那就執行程式前使用下列命令
ulimit -s unlimited

星期二, 12月 07, 2010

殘念~ ulimit -s unlimited 無法執行

一直以來,我改過的POM<--好啦我的功力差啦,因為用太多的allocate陣<--其實是全部的陣列都用allocate。所以執行時會有stack太小的問題啦。詳情與解法過程寫過了,就不再寫。總之就是用下面的指令:
ulimit -s unlimited
一直以來都沒問題,今天確出現下面的訊息…
-bash: ulimit: stack size: cannot modify limit: Operation not permitted
搞了半天,就是不給啦,大概就是你不是系統管理員,不給你改,(奇怪了,之前就沒這個問題,裝系統時也沒啥特別設定,不過我用的系統是CentOS4以後啦,現在這台是RHEL3)找了老半,總之要改下面這個檔案:
/etc/security/limits.conf
加一行:
*             hard    stack           unlimited
再重新登出/入就可以執行下面的指令了。
ulimit -s unlimited
至於為什麼……就懶得知道了。

把 shell 變數傳進 awk 程式當中

在寫shell scripts,gawk很常用吧…例如印file 的第一、二、五、六行
gawk '{print $1, $2, $5, $6}' file
如果想把第五,六行乘一個放大係數(如:10倍)
gawk '{print $1, $2, $5*10, $6*10}' file
上面這樣寫當然沒問題。但是為了方便,放大係數通常放到變數裏(就叫做SCALE好了)
SCALE=10
gawk '{print $1, $2, $5*$SCALE, $6*$SCALE}'  file
這樣就不行了…因為gawk自已也有變數,BASH也有變數,誰是誰要先弄清楚才行。
gawk變數設定方法是在' ' 的後面 與 輸入資料檔的前面(如果有的話) 設定。
改成如下:
SCALE=10
gawk '{print $1, $2, $5*sca, $6*sca}' sca=$SCALE file
注意,在gawk裏的變數是不用加"$"字符的。
有了這個,還可以對第n欄做累加。
gawk 'sum=sum+$1 {print $1, sum}' sca=$SCALE file
上面的指令會輸出file檔案裏的第一柵,以及第一欄的加總。

gawk 'sum=sum+$1; ss=ss+$2 {print $1, sum, $2, ss}' sca=$SCALE file
上面的指令會輸出file檔案裏的第一欄、第一欄的加總、第二欄與第二欄的加總。