Thursday, June 28, 2007

tree class of Ruby


class Tree
include Enumerable

attr_accessor :left, :right

def initialize(str)
@str = str
end

def each
left.each {|t| yield t } if left
right.each{|t| yield t } if right
yield @str
end

end

t1 = Tree.new('a')
t1.left = Tree.new('a_left')
t1.right = Tree.new('a_right')
t1.left.left = Tree.new('a_left_left')
t1.right.left = Tree.new('a_right_left')
t1.right.right = Tree.new('a_right_right')

t1.each {|t| puts t}

# >> a_left_left
# >> a_left
# >> a_right_left
# >> a_right_right
# >> a_right
# >> a

Ruby's module mixin

# All you have to do is write an iterator called each, which returns the elements of our collection in turn. Mix in Enumerable, and suddenly your class supports things such as map, include?, and find_all?. If the objects in your collection implement meaningful ordering semantics using the <=> method, you’ll also get methods such as min, max, and sort.


class A
include Comparable
include Enumerable
attr :n

def initialize(n)
@n = n
end

def each
(1..@n).each do |i|
yield i
end
end

def <=>(b)
self.n <=> b.n
end
end

a = A.new(3)
b = A.new(4)

m = a.map {|i| i.to_s + __LINE__.to_s}

p m

n = a > b

p n

Ruby Catch Throw Test


catch :label do
(1..10).each do |i|
(11..13).each do |j|
puts 'i=' + i.to_s + ', j=' + j.to_s
throw :label if i == 3 and j == 12
end
end
end

puts 'over'

SelectList object of WWW::Mechanize


require 'mechanize'

agent = WWW::Mechanize.new
agent.user_agent_alias = 'Windows IE 6'
page = agent.get('http://www.apple.com/')
form = page.forms[1]
select_list = form.field('worldwide')
p select_list

# WWW::Mechanize::SelectList


Wednesday, June 27, 2007

notes of ruby

Similarly, both or and || evaluate to true if either operand is true. They evaluate their
second operand only if the first is false. As with and, the only difference between or
and || is their precedence.
Just to make life interesting, and and or have the same precedence, and && has a higher
precedence than ||.

So how do the $-variables fit in? Well, after every pattern match, Ruby stores a refer-
ence to the result (nil or a MatchData object) in a thread-local variable (accessible
using $~). All the other regular expression variables are then derived from this object.
Although we can’t really think of a use for the following code, it demonstrates that all
the other MatchData-related $-variables are indeed slaved off the value in $~.
re = /(\d+):(\d+)/
md1 = re.match("Time: 12:34am")
md2 = re.match("Time: 10:30pm")
[ $1, $2 ] # last successful match → ["10", "30"]
$~ = md1
[ $1, $2 ] # previous successful match → ["12", "34"]

Ruby Block比较


class Array
def find
for i in 0 ... self.length
return self[i] if yield self[i]
end
return nil
end
end

a = [1, 2, 3, 4, 5]
puts a.find { |i|
i == 4
}
# error syntax
puts a.find do |i|
i == 4
end
# {...}比do...end块的结合能力强。例如:
#
# foobar a, b do .. end # foobar 是带块的方法
# foobar a, b { .. } # b 成了带块的方法

Tuesday, June 26, 2007

如何在Rails Session中存取模型对象object


当在controller中存放某个对象(比如是一个:对象)到Session中时,应用程序会报错,并抛出一个500错误,而不是Rails的错误(在存的时候不会错,但读取就报错,因为不能正常反序列化对象)。这需要在application.rb(contollers folder)中require此对象的class,重启Rails服务器进程重新打开浏览器即可。
另外也可以在controller中加上model声明,这样Rails就会预先加载对应的模型类,在反序列化的时候就能知道他们的类型定义。
class ApplicationController < ActionController::Base
model :user
end


在Rails SESSION中存放对象是有限制的,一般在session中的对象是要求可序列化的(用Ruby Marshal library),见programming ruby 2nd中说明:
Module Marshal
The marshaling library converts collections of Ruby objects into a byte stream, allowing them to be stored outside the currently active script. This data may subsequently be read and the original objects reconstituted.
对于不可序列化对象如I/O对象就能放入SESSION中。

url_encode and url_decode of Ruby


require "ERB"
require "uri"

old = "http://www.google.com/search?q=搜索&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:en-US:official&client=firefox-a"
# URI.escape(old):
new = " http://www.google.com/search?q=%CB%D1%CB%F7&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:en-US:official&client=firefox-a"
# ERB::Util.url_encode(old)与php中url_encode()相同:
url_encoded = "http%3A%2F%2Fwww.google.com%2Fsearch%3Fq%3D%CB%D1%CB%F7%26ie%3Dutf-8%26oe%3Dutf-8%26aq%3Dt%26rls%3Dorg.mozilla%3Aen-US%3Aofficial%26client%3Dfirefox-a"
# javascript encodeURIComponent: http%3A%2F%2Fwww.google.com%2Fsearch%3Fq%3D%E6%90%9C%E7%B4%A2%26ie%3Dutf-8%26oe%3Dutf-8%26aq%3Dt%26rls%3Dorg.mozilla%3Aen-US%3Aofficial%26client%3Dfirefox-a
# 跟url_encode中文字符的结果不同


puts URI.escape(old)
puts ERB::Util.url_encode(old)


puts URI.unescape(url_encoded)
puts URI.unescape(new)




Hpricot::ParseError of input tag


require "hpricot"


def test_buffer_error
Hpricot(%{<input type="hidden" name="content" value="#{('Xx' * 2000) * 20}" >})
end


test_buffer_error
Hpricot::ParseError in manage#reports
ran out of buffer space on element <input>, starting on line 1.


这里因为HTML里有个input的value值字符串过长造成的错误,这种文档用Hpricot处理之前需要先对其value做些处理。


Monday, June 18, 2007

Produce PNG barcode images from a Ruby on Rails application using RMagick and Gbarcode


This is a Ruby on Rails controller that produces PNG barcode images using RMagick (http://rmagick.rubyforge.org/) and Gbarcode (http://gbarcode.rubyforge.org/). You will need to install RMagick and Gbarcode.

On Mac OS X, you can use the Locomotive RMagick bundle (http://locomotive.raaum.org/bundles/index.html) if you install the gbarcode gem into it first, for instance:

% export GEM_HOME=/Applications/Locomotive2/Bundles/rmagickRailsMar2007_i386.locobundle/framework/lib/ruby/gems/1.8/
% gem install gbarcode

To use it, save this code as barcode_controller.rb in the apps/controllers directory of your Rails application. Generate the barcodes using a URL like this:

http://localhost:3000/barcode/send_barcode?string=A-string-to-encode


This example uses the BARCODE_128 encoding; you can use different barcode encodings by adjusting the code.


require 'RMagick'
require 'gbarcode'

class BarcodeController < ApplicationController

def send_barcode
@image_data = get_barcode_image
send_data(@image_data, :type => 'image/png',
:disposition => 'inline')
end

def get_barcode_image
string_to_encode = params[:string]
if string_to_encode.nil?
string_to_encode = "No string specified"
end
eps_barcode = get_barcode_eps(string_to_encode)
return convert_eps_to_png(eps_barcode)
end

def get_barcode_eps(string_to_encode)
bc = Gbarcode.barcode_create(string_to_encode)
Gbarcode.barcode_encode(bc, Gbarcode::BARCODE_128)
read_pipe, write_pipe = IO.pipe
Gbarcode.barcode_print(bc, write_pipe, Gbarcode::BARCODE_OUT_EPS)
write_pipe.close()
eps_barcode = read_pipe.read()
read_pipe.close()
return eps_barcode
end

def convert_eps_to_png(eps_image)
im = Magick::Image::read_inline(Base64.b64encode(eps_image)).first
im.format = "PNG"
read_pipe, write_pipe = IO.pipe
im.write(write_pipe)
write_pipe.close()
png_image= read_pipe.read()
read_pipe.close()
return png_image
end

end

Friday, June 15, 2007

[PLUGIN RELEASE] ActsAsReadonlyable

Introduction

ActsAsReadonlyable adds support of multiple read-only slave databases to ActiveRecord models. When a model is marked with acts_as_readonlyable, some of AR finders are overridden to run against a slave DB. The supported finders are find, find_by_sql, count_by_sql, find_[all_]by_*, and reload.

Finders can be forced to fall back to a default DB by passing the :readonly flag set to false.

Disclaimer

As our blog post points out, we wrote this plugin in preparation to using slave DBs but we are not going to have those until May 2007. So even though the code is covered with tests (see svn://rubyforge.org/var/svn/acts-as-with-ro/trunk/test/unit/read_write_model_test.rb), it has not been used outside of those. We would have a discovery period in May when the code is likely to be improved so for now you can use is at your own risk. Meanwhile, we would be happy to fix any issue revealed. Drop us a line at rails-trunk [ at ] revolution DOT com.

Using this plugin should not be your first step in application optimization/scaling or even the second one. Before installing it make sure you understand the implication of leveraging multiple DBs (for example, the potential for cross DB joins).

Usage

Add acts_as_readonlyable to your models backed up by slave DBs. If you want to apply ActsAsReadonlyable to all models, add this or similar code at the end of config/environment.rb:


class << ActiveRecord::Base

def read_only_inherited(child)
child.acts_as_readonlyable :read_only
ar_inherited(child)
end

alias_method :ar_inherited, :inherited
alias_method :inherited, :read_only_inherited

end

Example

Sample DB Config

dbs:

database: master_db
host: master-host

read_only:
database: slave_db
host: slave-host

Note: There is no need for more than one read-only database configuration in your database.yml since you can leverage traditional load balancing solutions. If you still want to use database.yml to spread the load, define multiple entries there and use acts_as_readonlyable [:first_read_only, :second_read_only].


Sample Model

class Fruit < ActiveRecord::Base
acts_as_readonlyable :read_only
end

Usage:

r = Fruit.find(:first) # executes against the read-only db
r.field = 'value'
r.save! # executes against the read/write db

r.reload # executes against the read-only db
r.reload(:readonly => false) # executes against the read/write db

Installation

As plugin:
script/plugin install svn://rubyforge.org/var/svn/acts-as-with-ro/trunk/vendor/plugins/acts_as_readonlyable


License

ActsAsReadonlyable released under the MIT license.


Support

The plugin RubyForge page is http://rubyforge.org/projects/acts-as-with-ro

Martin Fowler Keynote

Posted by Brian Eng on June 24, 2006

A little odd that he's been asked to give the keynote, since he's never used Ruby on Rails! (Although he's been using Ruby for a long time.) So he's going to be talking about something else instead...

Software Design

What makes good software design?
Opinionated software - don't try to be all things to all people
Active Record pattern - not that useful in an "enterprise" setting - but so what?
But if you can live in a world where Active Record makes sense, it makes life a lot easier.
He's never seen an Active Record implementation as complete or as useful as Rails.
One framework to do everything = disaster
The Rails core team vision should never change.
Simplicity
Java - enormous power, but overly complicated, for pretty much anything
Rails has further driven toward simplicity.
Two camps
VB/PHP - "We have great disdain for Visual Basic"
Enterprise - "1 week application in 9 months"
Quick and clean
Traditionally, to do something quick, it has to be dirty... to do something well, it takes a long time... no more!
Smalltalk - quick and clean - and Ruby/Rails continues that notion
Quick doesn't have to be dirty. There should more attention paid to that in software.
Testing as a key part of software development. With strong testing culture, a lot of the concerns with traditional software development go away.
Should someone you're doing work for care that you're using Rails (or any other technology)?

Yes, technology affects the whole of the conversation between developers and customers.
The secret, the hardest part of software development is building exactly what the customer needs.
Extreme Programming -> quick and clean -> conversational mode.
Find out what is needed by a mutual process of exploration.
Don't spend a lot of time aiming. Just fire.
Drive down cycle time by using short iterations and engaging the customer in the process.
In order to get the cycle time down, you need the technology and tools to do that. This is where Rails comes in.
Physical proximity (on-site customer) is important. But you've got have something to show them. Again, Rails.
In this age of Web 2.0 (TM)... there is this culture of just give the product to the customer. Then see how they use it. Ship the product, then gather the requirements. The opposite of the traditional process. Fire, aim, fire, aim. As long as the bullets are cheap.
Technical plumbing is interesting to some people. But mapping the software to the business problem is really interesting. Rails makes the technical plumbing stuff go away.
The best value occurs when software people work hand-in-hand with business people. This is a very important cultural shift that Rails is helping to enable.
Ruby

Ruby just suits me better than Perl, Python, Java.
Rails is important because it drives interest in Ruby.
Rails is successful because of the power of Ruby.
Rails is so simple, it's really Ruby that is important.
We shouldn't even be having RailsConf!
One of Smalltalk's greatest failures - it wants to be everything
Post-Modernism's notion = everything is the same
Even a nice system, beautifully designed, is basically the same as the next.
The heart of Ruby's success is that it's aware that it is a hodgepodge of stuff. Rails only part of the solution. It's about being to throw a bunch of stuff together to create a working solution. Not a very controlled environment. Here are the complexities and inconsistencies - deal with it. Ruby and Rails encourages that.
One last reason Ruby and Rails is important: the people in the community. And it's the most important thing.

Thursday, June 14, 2007

while and until Modifiers

expression while boolean-expression
expression until boolean-expression
If expression is anything other than a begin/end block, executes expression zero or
more times while boolean-expression is true (for while) or false (for until).
If expression is a begin/end block, the block will always be executed at least one time.

Wednesday, June 13, 2007

Ruby class_eval example


C = Class.new
C.class_eval do
def some_method
puts "Created in class_eval"
end
end
c = C.new
c.some_method

var = 'test class_eval'
C.class_eval {define_method('talk') {puts var}}
c.talk

利用mechanize获取gmail


require 'rubygems'
require 'mechanize'

agent = WWW::Mechanize.new

page = agent.get 'http://www.gmail.com'
form = page.forms.first
form.Email = 'gmailacc'
form.Passwd = 'gmailpasswd'
page = agent.submit form

page = agent.get page.search("//meta").first.attributes['href'].gsub(/'/,'')
page = agent.get page.uri.to_s.sub(/\?.*$/, "?ui=html&zy=n")
page.search("//tr[@bgcolor='#ffffff']") do |row|
from, subject = *row.search("//b/text()")
url = page.uri.to_s.sub(/ui.*$/, row.search("//a").first.attributes["href"])
puts "From: #{from}\nSubject: #{subject}\nLink: #{url}\n\n"

email = agent.get url
# ..
end


http://schf.uc.org/articles/2007/02/14/scraping-gmail-with-mechanize-and-hpricot

scrap google search results use hpricot

require 'rubygems'
require 'cgi'
require 'open-uri'
require 'hpricot'

q = %w{david cain pc}.map { |w| CGI.escape(w) }.join("+")
url = "http://www.google.com/search?q=#{q}"
doc = Hpricot(open(url).read)
urls = (doc/"div[@class='g'] a")
urls.each {|url| puts url['href']}

Saturday, June 09, 2007

Windows XP and DOS[Unix Style Tail Command]

SUMMARY: Display the most recent results of a log file with the tail command for Windows XP

The tail command, on most Unix-style operating systems, lets you display the last 10 or so lines of a text file. It also supports a feature allowing you to keep a file lock on a particular file, displaying new lines as they appear. This is most commonly used for displaying the results of log or debug files, letting you see only the most recent activity of a particular process.

While Windows XP does not normally come with a 'tail' tool, it is available in the Windows 2003 Resource Kit. It is a large download, but besides the 'tail' command, the Windows 2003 Resource Kit also provides tools to remap keys, query the Active Directory, and more. To download and install the Resource Kit:

1. Go to the Microsoft Windows Server 2003 download section at http://www.microsoft.com/windowsserver2003/
downloads/tools/default.mspx. Or, if that link does not work, visit http://www.microsoft.com/ and search for "Windows 2003". Once there, choose the "Downloads -> Tools" link.

2. Select the link "Windows Server 2003 Resource Kit Tools".

3. Click the "Download" link. Choose to register or not, depending on your choice, and follow the on-screen instructions to download and install the product. The default install directory is "C:\Program Files\Windows Resource Kits\Tools\".

Once the Windows 2003 Resource Kit is installed, you may need to reboot your machine for the directory "C:\Program Files\Windows Resource Kits\Tools\" to be added to your path.

Now that the tail command is available, to see the online help, enter the following DOS command:

tail /?

Here is a command summary:

C:\>tail FILENAME

Display the last ten lines from file FILENAME. For example, to see the last ten activities made by the Windows Update tool, issue these commands:

C:\>c:
C:\>cd \windows
C:\>tail "Windows Update.log"

C:\>tail -n FILENAME

Display the last 'n' lines from file FILENAME. For example, view the last 20 lines in the Windows Setup log:

C:\>c:
C:\>cd \windows
C:\>tail -20 setuplog.txt

C:\>tail -f FILENAME

Keep accesing FILENAME, displaying new lines as necessary.

To see this feature in action, open up a new file in Notepad, write the word 'hello, world', and save it as c:\test.log. Keep the file open in Notepad. Now, issue the following DOS commands:

C:\>c:
C:\>cd \
C:\>tail -f test.log

You should see the word 'hello, world' in your DOS prompt. Now, go back to Notepad and write the text "Process executed." Save the file. The DOS prompt should now say "Process executed." Whatever you add to the file in Notepad should then appear in your DOS prompt until you terminate the command.

mysql5 中的事务回滚ROLLBACK说明

1. 不能回滚的语句
有些语句不能被回滚。通常,这些语句包括数据定义语言(DDL)语句,比如创建或取消数据库的语句,和创建、取消或更改表或存储的子程序的语句。
2. 会造成隐式提交的语句
以下语句(以及同义词)均隐含地结束一个事务,完成SQL后即进行了一个COMMIT。
ALTER FUNCTION, ALTER PROCEDURE, ALTER TABLE, BEGIN, CREATE DATABASE, CREATE FUNCTION, CREATE INDEX, CREATE PROCEDURE, CREATE TABLE, DROP DATABASE, DROP FUNCTION, DROP INDEX, DROP PROCEDURE, DROP TABLE, LOAD MASTER DATA, LOCK TABLES, RENAME TABLE, SET AUTOCOMMIT=1, START TRANSACTION, TRUNCATE TABLE, UNLOCK TABLES.
如在InnoDB中用TRUNCATE TABLE语句删除了一个表之后就不能用ROLLBACK进行恢复:Truncate table is an Oracle SQL extension adopted in MySQL and cannot roll back a truncate statement in Oracle.
3. 如果在事务中使用非事务安全型表(例如:MyISAM),则对这些表的任何变更被立刻存储,不论autocommit模式的状态如何。
4. 在默认autocommit=1情况下,使用START TRANSACTION,autocommit仍然被禁用,直到使用COMMIT或ROLLBACK结束事务为止。然后autocommit模式恢复到原来的状态。如下SQL:


mysql> show create table users\G
*************************** 1. row ***************************
Table: users
Create Table: CREATE TABLE `users` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(255) NOT NULL,
`hashed_password` varchar(255) default '',
`email` varchar(255) default NULL,
`created_at` datetime default NULL,
`updated_at` datetime default NULL,
`last_login` datetime default NULL,
PRIMARY KEY (`id`),
KEY `users_name_index` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

mysql> select name from users;
+-------+
| name |
+-------+
| admin |
| yu |
+-------+
2 rows in set (0.00 sec)

mysql> set SESSION autocommit=1;
Query OK, 0 rows affected (0.00 sec)

mysql> select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
| 1 |
+--------------+
1 row in set (0.00 sec)

mysql> select name from users;
+-------+
| name |
+-------+
| admin |
| yu |
+-------+
2 rows in set (0.00 sec)

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> update users set name = 'davidyu' where name = 'yu';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0

mysql> select name from users;
+---------+
| name |
+---------+
| admin |
| davidyu |
+---------+
2 rows in set (0.01 sec)

mysql> select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
| 1 |
+--------------+
1 row in set (0.00 sec)

mysql> ROLLBACK;
Query OK, 0 rows affected (0.00 sec)

mysql> select name from users;
+-------+
| name |
+-------+
| admin |
| yu |
+-------+
2 rows in set (0.00 sec)

Rails with multiple databases

code In database.yml
slave1:
host: 18.48.43.29 # your slave’s IP
database: production
username: root
password: pass
l Define a model Slave1.rb


class Slave1 < ActiveRecord::Base
self.abstract_class = true
establish_connection :slave1
end

When you need to run a query on the slave, just do
Slave1.connection.execute("select * from some_table")

Magic Multi-Connections Ruby on Rails ActiveRecords

Wednesday, June 06, 2007

mongrel_rails service::start ERROR

E:\works>mongrel_rails service::install -N search -c E:\works -p 3000 -e production
Mongrel service 'search' installed as 'search'.

E:\works>mongrel_rails service::start -N search
ERROR RUNNING 'service::start': Plugin /service::start does not exist in category /commands
Use help command to get help

http://rubyforge.org/pipermail/mongrel-users/2007-February/002962.html

> Is there an expected release date for the fixed version of
> mongrel_service that will resolve the missing service::start command?

No, it wouldn't. ::start and ::stop commands where removed since they
duplicate simple functionality found built in windows.

The same you achieve calling mongrel_rails service::start -N myservice
could be done with just 3 words at the command line:

net start myservice

Doing a simple comparison:

"mongrel_rails service::start -N myservice".length
=> 41
"net start myservice".length
=> 19

Guess which one wins? This is also valid for stop (4 letters).

> I would love to use the much improved features of the new
> mongrel_service, but I haven't been able to yet.

Why? you only need to remove and then reinstall the service (::remove
and then ::install again).

Tuesday, June 05, 2007

/var/log目录中一些重要的记录档案的说明

1. /var/log/lastlog : 记录每个使用者最近签入系统的时间, 因此当使用者签入时, 就会显示其上次签入的时间, 您应该注意一下这个时间, 若不是您上次签入的时间, 表示您的帐号可能被人盗用了. 此档可用 /usr/bin/lastlog 指令读取.
2. /var/run/utmp : 记录每个使用者签入系统的时间, who, users, finger 等指令会查这个档案.
3. /var/log/wtmp : 记录每个使用者签入及签出的时间, last 这个指令会查这个档案. 这个档案也记录 shutdown 及 reboot 的动作.
4. /var/log/secure : 记录那些站台连线进来, 以及那些位址连线失败.
5. /var/log/maillog : 记录 sendmail 及 pop 等相关讯息.
6. /var/log/cron : 记录 crontab 的相关讯息
7. /var/log/dmesg : /bin/dmesg 会将这个档案显示出来, 它是开机时的画面讯息.
8. /var/log/xferlog : 记录那些位址来 ftp 拿取那些档案.
9. /var/log/messages : 系统大部份的讯息皆记录在此, 包括 login, check password , failed login, ftp, su 等.
lastlog 及 utmp 的结构在 /usr/include/utmpbits.h 中.
wtmp 的格式和 utmp 相同.
文章来源于网络,可能是鸟哥的文章。

Sunday, June 03, 2007

prints a color table of 8bg * 8fg * 2 states (regular/bold)


#!/bin/bash

# prints a color table of 8bg * 8fg * 2 states (regular/bold)
echo
echo Table for 16-color terminal escape sequences.
echo Replace ESC with \\033 in bash.
echo
echo "Background | Foreground colors"
echo "---------------------------------------------------------------------"
for((bg=40;bg<=47;bg++)); do
for((bold=0;bold<=1;bold++)) do
echo -en "\033[0m"" ESC[${bg}m | "
for((fg=30;fg<=37;fg++)); do
if [ $bold == "0" ]; then
echo -en "\033[${bg}m\033[${fg}m [${fg}m "
else
echo -en "\033[${bg}m\033[1;${fg}m [1;${fg}m"
fi
done
echo -e "\033[0m"
done
echo "--------------------------------------------------------------------- "
done

echo
echo

colortable16.sh
shell> ruby -e 'print "\e[33m"'
shell> ruby -e 'print "\e[0m"'
shell> ruby -e 'print "\e[1m"'
shell> printf "\e[0m"
shell> echo -e "\e[1m"
shell> echo -e "\033[47m\033[1;31mBright red on white.\033[0m"

Saturday, June 02, 2007

[转]Bash 编程

作者:jiupima(CU)
一. Bash特殊字符
1. 通配符:
*:匹配任何字符串
?:匹配任何单个字符
集合运算符:用一些单个字、一个连续范围或断续的字符集合作为通配符
[set]:用字符集合作通配符匹配单个字符,如:[aeiou],[a-o],[a-h, w-z]
[!set]:除了集合外的所有字符组成的集合作通配符
2. 花括号展开式(可以嵌套):
格式:[前导字符串]{字符串1[{嵌套字符串1…}] [, 字符传2…]}[后继字符串]
如:c{a{r, t, n}, b{r, t, n}}s 就等于 cars cats cans cbrs cbts cbns
3. 其它特殊字符:
< :输入重定向
> :输出重定向(没有文件则创建,有则覆盖)
>> :输出重定向(没有则创建,有则追加到文件尾部)
( :子shell开始,子shell继承父shell部分环境变量
) :子shell结束
{ :命令块开始,由当前shell执行,保留所有环境变量
} :命令块结束
| :管道
\ :引用后面的单个字符
‘ :强引用字符串,不解释特殊字符
“ :弱引用字符串,解释所有特殊字符
~ :根目录
` :命令替换
; :命令分隔符(命令终止符),运行在一行里执行多条命令
# :行注释
$ :变量表达式
& :在后台执行命令
* :字符串通配符
? :单个字符通配符

二. Bash变量
1. 自定义变量
用户自定义的变量由字母、数字和下划线组成,并且变量名的第一个字符不能为数字,且变量名大小写敏感。
varname=value 注意bash不能在等号两侧留空格
shell语言是非类型的解释型语言,给一个变量赋值实际上就是定义了变量,而且可以赋不同类型的值。引用变量有两种方式,$varname和${varname},为防止变量在字符串中产生歧义建议使用第二种方式,引用未定义的变量其值为空。
为一个变量赋值一个串,需要用到引号,注意`、’、”的不同,``相当于$()
为了使变量可以在其它进程中使用,需要将变量导出:export varname
2. 环境变量
可以用set命令给变量赋值或查看环境变量值,使用unset命令清除变量值,使用export导出变量将可以使其它进程访问到该环境变量。
3. 位置变量
位置变量对应于命令行参数,其中$0为脚本名称,$1为第一个参数,依次类推,参数超过9个必须使用${}引用变量。shell保留这些变量,不允许用户以另外的方式定义它们,传给脚本或函数的位置变量是局部和只读的,而其余变量为全局的(可以用local关键字声明为局部)。
4. 其它变量
$? :保存前一个命令的返回码
$- :在Shell启动或使用set命令时提供选项
$$ :当前shell的进程号
$! :上一个子进程的进程号
$# :传给脚本或函数的参数个数,即位置变量数减1,不含脚本名称。
$* :传给脚本或函数的参数组成的单个字符串,即除脚本名称后从第一个参数开始的字符串,每个参数以$IFS分隔(一般内部域分隔符$IFS为1空格)。形同”…”
$@ :传给脚本或函数的参数列表,这些参数被表示为多个字符串。形同”” “” “”…。$*和$@之间的不同方便使用两种方法处理命令行参数,但是在打印时参数外观没有区别。
如: #vi posparm.sh
function cutparm
{echo –e “inside cntparm: $# parms: $*\n”}
cntparm “$*”
cntparm “$@”
#./posparm.sh abc bca cab
inside cntparm: 1 parms: abc bca cab
inside cntparm: 3 parms: abc bca cab

三. Bash操作符
1. 字符串操作符(替换操作符)
${var:-word} 如果var存在且不为空,返回它的值,否则返回word
${var:=word} 如果var存在且不为空,返回它的值,否则将word赋给var, 返回它的值
${var:+word} 如果var存在且不为空,返回word,否则返回空
${var:?message} 如果var存在且不为空,返回它的值,
否则显示“bash2:$var:$message”,然后退出当前命令或脚本
${var:offset[:length]} 从offset位置开始返回var的一个长为length的子串,
若没有length,则默认到var串末尾
2. 模式匹配操作符
${var#pattern} 从var头部开始,删除和pattern匹配的最短模式串,然后返回 剩余串
${var##pattern} 从var头部开始,删除和pattern匹配的最长模式串,然后返回 剩余串,basename path=${path##*/}
${var%pattern} 从var尾部开始,删除和pattern匹配的最短模式串,然后返回 剩余串,dirname path=${path%/*}
${var%%pattern} 从var尾部开始,删除和pattern匹配的最长模式串,然后返回 剩余串
${var/pattern/string} 用string替换var中和pattern匹配的最长模式串

四. Shell中条件和test命令
Bash可以使用[ … ]结构或test命令测试复杂条件
格式:[ expression ] 或 test expression
返回一个代码,表明条件为真还是为假,返回0为真,否则为假。
注:左括号后和右括号前空格是必须的语法要求
1. 文件测试操作符
-d file file存在并且是一个目录
-e file file存在
-f file file存在并且是一个普通文件
-g file file存在并且是SGID(设置组ID)文件
-r file 对file有读权限
-s file file存在并且不为空
-u file file存在并且是SUID(设置用户ID)文件
-w file 对file有写权限
-x file 对file有执行权限,如果是目录则有查找权限
-O file 拥有file
-G file 测试是否是file所属组的一个成员
-L file file为符号链接
file1 –nt file2 file1比file2新
file1 –ot file2 file1比file2旧
2. 字符串操作符
str1=str2 str1和str2匹配
str1!=str2 str1和str2不匹配
str1<str2 str1小于str2
str1>str2 str1大于str2
-n str str的长度大于0(不为空)
-z str str的长度为0(空串)
3. 整数操作符
var1 –eq var2 var1等于var2
var1 –ne var2 var1不等于var2
var1 –ge var2 var1大于等于var2
var1 –gt var2 var1大于var2
var1 –le var2 var1小于等于var2
var1 –lt var2 var1小于var2
4. 逻辑操作符
!expr 对expr求反
expr1 && expr2 对expr1与expr2求逻辑与,当expr1为假时不再执行expr2
expr1 || expr2 对expr1与expr2求逻辑或,当expr1为真时不再执行expr2
注:另一种逻辑操作符 逻辑与expr1 –a expr2 逻辑或expr1 –o expr2

五. Shell流控制
1. 条件语句:if
if 条件 IFS=:
then for dir in $PATH
语句 do
[elif 条件 if [ -O dir ]; then
语句] echo –e “\tYou own $dir”
[else else
语句] echo –e “\tYou don’t own $dir”
fi fi
2. 确定性循环:for done
for value in list for docfile in /etc/* /usr/etc/*
do do
statements using $value cp $docfile ${docfile%.doc}.txt
done done
注:for var;… 相当于for var in “$@”;…
3. 不确定性循环:while和until
while 条件 until 条件
do do
语句 语句
done done

count=1 count=1
while [ -n “$*” ] until [ -z “$*” ]
do do
echo "parameter $count" echo "parameter $count"
shift shift
count='expr $count + 1' count='expr $count + 1'
done done
条件为真执行循环体 条件为假执行循环体
注:整数变量的定义与算法
declare –i idx 定义整数变量 使用$(())无需定义
idx=1
while [ $idx!=150 ]
do
cp somefile somefile.$idx
idx=$idx+1 整数算法 idx=$(( $idx+1 ))
done
另一种算法 echo $(( 100/3 )) 将加减乘除表达式放入$(())中
4. 选择结构:case和select
case 表达式 in 表达式和模式依次比较,执行第一个匹配的模式
模式1) ;;使程序控制流跳到esac后执行,相当于break
语句;; 允许表达式和含有通配符的模式进行匹配
模式2)
语句;;
……
[*)
语句]
esac

select value [ in list ] 按list列表自动生成菜单
do 若没有list则默认为位置变量
statements using $value
done
如:IFS=: 设置域分隔符为:号
PS3=”choice>” 改变select默认提示符
clear
select dir in $PATH
do
if [ $dir ]; then
cnt=$(ls –Al $dir | wc -l)
echo “$cnt files in $dir”
else
echo “No such choice !”
fi
echo –e “\npress ENTER to continue, CTRL-C to quit”
read 使程序按回车继续,ctrl+c退出
clear
done
5. 命令shift
将存放在位置变量中的命令行参数依次向左传递
shift n 命令行参数向左传递n个串
六. Shell函数
定义: function fname fname ()
{ {
commands commands
} }
调用:fname [ parm1 parm2 parm3 ... ]
说明: 函数在使用前定义,两种定义功能相同
函数名和调用函数参数成为函数的位置变量
函数中的变量应该使用local声明为局部变量

七. 输入输出
限于篇幅,这里不讨论所有输入输出操作符和功能
1.I/O重定向
< :输入重定向
> :输出重定向(没有文件则创建,有则覆盖)
>> :输出重定向(没有则创建,有则追加到文件尾部)
<< :输入重定向(here文档)
格式: command << label
input…
label
说明: 使一个命令的输入为一段shell脚本(input…),直到标号(label)结束
如: cat < $HOME/.profile > out
echo “add to file end !” >> $HOME/.profile
ftp:USER=anonymous
PASS=YC@163.com
ftp –i –n << END -i:非交互模式 -n:关闭自动登录
open ftp.163.com
user $USER $PASS
cd /pub
close
END END标记输入结束
2.字符串I/O操作
字符串输出:echo
命令选项: -e:启动转义序列 -n:取消输出后换行
转义序列: \a:Alt/Ctrl+G(bell) \b:退格Backspace/Ctrl+H
\c:取消输出后换行 \f:Formfeed/Ctrl+J
\r:Return/Ctrl+M \v:Vertical tab
\n:八进制ASCII字符 \\:单个\字符 \t:Tab制表符
字符串输入:read
可以用于用户交互输入,也可以用来一次处理文本文件中的一行
命令选项: -a:将值读入数组,数组下标从0开始
-e:使用GNU的readline库进行读入,允许bash的编辑功能
-p:在执行读入前打印提示
如: IFS=:
read –p “start read from file . filename is : \c” filename
while read name pass uid gid gecos home shell < filename
do
echo –e “name : $name\npass : $pass\n”
done
说明:如果行的域数大于变量表的变量数,则后面的域全部追加给最后的变量

八. 命令行处理
命令行处理命令:getopts
有两个参数,第一个为字母和冒号组成的选项列表字符串,第二个为一个变量名
选项列表字符串以冒号开头的选项字母排列组成,如果一选项需要一个参数则该选项字母后跟一个冒号
getopts分解第一参数,依次将选项摘取出来赋给第二个参数变量
如果某选项有参数,则读取参数到内置变量OPTARG中
内置变量OPTIND保存着将被处理的命令行参数(位置参数)的数值
选项列表处理完毕getopts返回1,否则返回0
如: while getopts “:xy:z:” opt
do
case $opt in
x) xopt=’-x set’ ;;
y) yopt=”-y set and called with $OPTARG” ;;
z) zopt=”-z set and called with $OPTARG” ;;
\?) echo ‘USAGE: getopts.sh [-x] [-y arg] [-z arg] file…’
exit 1
esac
done
shift ($OPTING-1) 将处理过的命令行参数移去
echo ${xopt: -‘did not use –x‘}
echo ${yopt: -‘did not use –y‘}
echo ${zopt: -‘did not use –z‘}

echo “Remaining command-line arguments are :”
for f in “$@”
do
echo –e “\t$f\n”
done

九. 进程和作业控制
信号处理命令:trap
格式:trap command sig1 sig2 …
trap可以识别30多种信号,如中断(Ctrl+c)、挂起(Ctrl+z)等,可以使用kill -l查看信号清单
当脚本接受到信号sig1、sig2等,trap就执行命令command,command完成后脚本重新执行
信号可以通过名称或数字来标识
作业控制命令:bg、fg
bg:显示后台进程,即用Ctrl+z挂起或‘命令 &’执行的进程
fg:将后台进程转到前台执行
kill –9 %n:杀掉第n个后台进程
附录:
一. Bash支持的命令行参数
-a 将所有变量输出 
  -c "string"从string中读取命令 
  -e 使用非交互式模式 
  -f 禁止shell文件名产生 
  -h 定义 
  -i 交互式模式 
  -k 为命令的执行设置选项 
  -n 读取命令但不执行 
  -r 受限模式 
  -s 命令从标准输入读取 
  -t 执行一命令,然后退出shell 
  -u 在替换时,使用未设置的变量将会出错 
  -v 显示shell的输入行 
  -x 跟踪模式,显示执行的命令
许多模式可以组合起来用,使用set可以设置或取消shell的选项来改变shell环境。打开选项用"-",关闭选项用"+",若显示Shell中已经设置的选项,执行: $echo $-

二. .profile中shell的环境变量意思如下: 
CDPATH 执行cd命令时使用的搜索路径 
HOME 用户的home目录 
IFS 内部的域分割符,一般为空格符、制表符、或换行符 
MAIL 指定特定文件(信箱)的路径,有UNIX邮件系统使用 
PATH 寻找命令的搜索路径(同dos的config.sys的 path) 
PS1 主命令提示符,默认是"$" 
PS2 从命令提示符,默认是">" 
TERM 使用终端类型

Friday, June 01, 2007

Ruby On Rails With Apache and mod_proxy using .htaccess

If you want your rails app in the same apache html directory, use a .htaccess like this :

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule (.*) http://localhost:3000/$1 [P]