oyaji's Blog

rails model associations

 

Rails中ActiveRecord finders不允许我们在include预加载关联对象时使用select。
 
例如这样的情况:
 
class Student < ActiveRecord::Base
   has_many :calls
   has_one :call
end

class Call < ActiveRecord::Base
   belongs_to :student
end
希望在显示student时,显示它的最近更新的call的日期。
 
改善前:
 
@students = Student.all(:include => [:call])
改善后:
 
#include eql left outer join
@students = Student.all(:select => "students.id, students.login, students.called_times,
calls.updated_at as last_called_at", :joins => "left outer join calls on students.id = calls.student_id")
 
前几天在rails performance turning中发现:
跨数据库的应用中在model层指定associations,以及用include实现的提前装载,
和through实现的多表关联,都不起作用。
但奇怪的是在console中却能正常的取到值。。。求解
 
 

rails benchmark

 

命令行工具


benckmark

#ruby script/performance/benchmarker 3 "Product.find :all"

执行3次Product.find :all, 输出结果中real列为实际运行所消耗的时间

profiler

#ruby script/performance/profiler "Product.find :all" 10

执行10次Product.find :all, 列出所有涉及到的类库的运行时间

 

测试用例


比如测试View中某段代码的执行时间,

 

<% benchmark("Showing projects partial") do %>
   <%= render :partial => @projects %>
<% end %>

 

Model中测试,

 

Project.benchmark("Creating project") do
  project = Project.create("name" => "stuff")
   project.create_manager("name" => "David")
   project.milestones << Milestone.find(:all)
end

 

日志


Rails生成的日志,

Processing ItemsController#index (for 127.0.0.1 at 2009-01-08 03:06:39) [GET]

Rendering template within layouts/items

Rendering items/index

Completed in 5ms (View: 2, DB: 0) | 200 OK [http://0.0.0.0/items]

总的请求时间是5ms, View占了2ms, DB为0, 其他3ms为Controller占用,可以用shell来分析反应慢的请求

 

具体见这里

rails cache 学习

 

在Rails中做缓存是简单的,要开启cache的话

config.action_controller.perform_caching = true 

默认情况下只有production是true,其他ENV都是false。

Rails中存储cache的方式多了去了,现在用的最多的应该是memcache吧。rails的guildes中有句Page caches are always stored on disk,貌似是所有的page cache都用filestore?在environment.rb中指定使用的store模式

ActionController::Base.cache_store = :file_store, "/path/to/cache/dir" 

只要上面两句话都配置好了,下面就简单的在需要cache的地方加几条语句就成

1、Fragment cache

就是缓存一个片段,将需要缓存的内容放入一个block中即可

<% cache do %>
  something to cache
<% end %>

如果要expire一个片段可以用expire_fragment方法,

expire_fragment(:controller => 'articles', :action => 'list')

2、Page cache和Action cache

class Article < AR::Base
  before_filter :authenticate, :only => [:edit, :create]
  caches_page :index
  caches_action :edit

  def index;end
  def edit;end
  def create
    expire_page :action => 'index'
    expire_action :action => 'edit'
  end
end

貌似caches_action和caches_page的区别也就只是action需要request经过一次rails stack,那也就能给要cache的action加点filter了;而page的话就完全不会经过rails了,直接就访问静态缓存的文件去了。。。

3、使用Sweeper管理cache

Swepper就是一个Observer,会在监视到一个特定的Model发生某些特定的callback时执行特定的活动,比如expire缓存

class ArticleSweeper < AC::Caching::Sweeper
  observe Article
  def after_create
    expire_page :controller => 'articles', :action => 'index'
    expire_action :controller =>' articles', :action => 'edit'
    expire_fragment :controller => 'articles', :action => 'list'
  end
end

4、浏览器端的缓存

通过stale?方法来判断Headers中的etag和last_modifiled是否与server上的一致

def show
  @article = Article.find(params[:id])
  if stale?(:etag => @article, :last_modifiled=>@article.updated_at.utc)
    respond_to do |format|
    end
   end
end

然后就是memcache相关的了,有时间再记录

 

 

cache and sweeper in rails

 

以关键字来分组显示列表,往往因为查询的数据量大,导致页面打开慢。使用cache action可以大大提高速度。

需要通过sweeper监控model的增删改动作,定时清理缓存。

models:

 

 

class TagPage < Page
  has_one :extra, :class_name => "TagPageExtra", :autosave => true
end
 
class TagPageExtra < ActiveRecord::Base
  belongs_to :tag_page
end

TagPage是扩展了以前的代码,对于新增的属性,通过TagPageExtra来处理。

controller:

class TagPagesController < ApplicationController
  caches_action :list
 
  def list
    @pages = TagPage.all(:select => "pages.id, pages.title, pages.description", :include => [:extra],
: order => "tag_page_extras.position")
  end
 
end
sweeper:
#文件放在 app/sweepers文件夹下
#并在environment中添加 文件路径
onfig.load_paths += %W( #{RAILS_ROOT}/app/sweepers )
 
class TagPageSweeper < ActionController::Caching::Sweeper
  observe TagPage
 
   def after_create(obj)
    expire_cache_for(obj)
  end
 
  def after_destroy(obj)
    expire_cache_for(obj)
  end
 
  def after_update(obj)
    expire_cache_for(obj)
  end
 
  private
  def expire_cache_for(obj)
    expire_action(list_tag_pages_path)
  end
end
 
#注意要在application controller中声明 才会起作用
class ApplicationController < ActionController::Base
  cache_sweeper :tag_page_sweeper
end

view:

 

<%= t("records_not_found")  if @pages.blank? %>
<dl>
  <% @pages.group_by(&:description).each do |description, pages| %>
  <dt><%= link_to description.nil? ? "<b>null</b>" : "<b>#{description}</b>", tag_pages_path(:tag => description) %></dt>
  <dd>
    <ul>
    <% pages.each do |page| %>
      <li class="tag"><%= link_to page.title, edit_tag_page_path(page) %></li>
    <% end %>
    </ul>
  </dd>
  <% end %>
</dl>
 

结果:
ProcessingTagPagesController#list (for xxx.xxx.xxx.xxx at 2010-07-08 09:24:03) [GET]
Filter chain halted as [#<ActionController::Filters::AroundFilter:0xb60d27d8 @identifier=nil,
@kind=:filter, @method=#<Proc:0xb79b6ba0@/usr/lib/ruby/gems/1.8/gems/actionpack-2.3.4/lib/action_controller/caching/actions.rb:64>,
@options={:only=>#<Set: {"list"}>, :if=>nil, :unless=>nil}>] did_not_yield.
Completed in 8ms (View: 0, DB: 0) | 200 OK [http://www.xxxx.com/tag_pages/list]
这次直接读取了缓存 DB查询为0.

item_list

 
****************************

来自IBM 的文章:

真实世界中的 Rails: 

rails中的缓存    高级页面缓存    优化ActiveRecord

这个文章超好,尤其是第一篇**************

×××××××××××××××××

 

Rails缓存总览:Caching with Rails: An overview
 
大家都会用到缓存。本指南将会告诉你如何减少数据库的访问次数并且在很短时间内向用户提供他们要的东西。
 
缓存基础 Basic Caching
 
这是一个不适用任何第三方插件的关于rails自带的3种类型的缓存技术的介绍。
 
在我们开始之前,确保 config/enviroments/*.rb 中的development.rb 中 config.action_controller.perform_caching 被设置为True,默认状态下, 开发环境和测试环境这行都被注释掉的,只有生产环境中是默认被打开的。
 
Ruby代码 
config.action_controller.perform_caching = true  
 
1.1 页面缓存 Page Caching
 
页面缓存是Rails机制,允许只通过web服务器调用一个已经实际生成的页面,而不需要通过rails堆栈来呈现给用户,速度超级快。不幸的是,他不能提供很多情况下的支持,比如一个需要验证用户身份的页面的情况。并且在页面缓存中,web服务器直接调用文件系统种的一个页面缓存文件,因此还需要建立缓存失效策略,比如你更新了应该显示的页面内容等等。
 
那么,你要如何来使用这个超级快的缓存呢?简单,假设你有一个叫ProductsController的控制器 和 一个会列出所有商品的叫 list 的action。
 
Ruby代码 
class ProductsController < ActionController  
  caches_page :index  
  
  def index  
  end  
end  
 
当products/index第一次被访问的时候,Rails会创建一个名为index.html的文件,在那以后,web服务器会在下次收到products/index访问请求的时候直接调用那个静态文件。
 
默认情况下,页面缓存的文件夹在rails根目录的 public文件夹下。这个可以通过改变配置
 
Ruby代码 
setting config.action_controller.page_cache_directory  
 
来设置。修改默认的/public存储位置有利于在你可能想他别的静态文件放在public中的时候避免文件名的命名冲突。修改这个设置的同时,还需要配置你的web服务器,否则他会找不到你的缓存文件。
 
页面缓存机制会为没有扩展名的页面请求自动的添加.html扩展名,来让web服务器很容易的找到这些页面。这个也可以通过改变配置文件来进行设置:
 
Ruby代码 
config.action_controller.page_cache_extension  
 
为了在新添加商品后,让页面缓存失效,你可以像这样来写你的products控制器:
 
Ruby代码 
class ProductsController < ActionController  
  
  caches_page :index  
  
  def index; end  
  
  def create  
    expire_page :action => :index  
  end  
  
end  
 
如果你想要一个更复杂的缓存失效计划,你可以使用缓存清道夫(sweepers)来让当缓存原来的对象改变时让缓存过期。这个在在Sweepers那节有讲述。
 
注意:页面缓存会无视所有的参数,所以 /products/list?page=1 在缓存文件系统中生成的文件是 /products/list.html。如果有人访问/proucts/list?page=2 ,那么他得到的结果和 page=1 是一样的。所以你应当注意页面缓存中URL使用GET参数的情况。
 
1.2 动作缓存 Action Caching
 
不能使用页面缓存的情况之一就是你不能将其用于那些需要身份验证的页面。这个时候你就可以使用动作缓存。动作缓存的工作原理和页面缓存差不多,只是 web请求会从web服务器传递给Rails解析器和Action Pack,这样以来过滤器就可以在缓存被调用以前生效。这样你就可以使用身份验证和别的一些限制,同时输出缓存副本。
 
清除Action缓存和页面缓存的方式完全相同。
 
比方说,你只是想验证用户编辑或者创建一个产品,但是仍然缓存这些页面:
 
Ruby代码 
class ProductsController < ActionController  
  
  before_filter :authenticate, :only => [ :edit, :create ]  
  caches_page :index  
  caches_action :edit  
  
  def index; end  
  
  def create  
    expire_page :action => :index  
    expire_action :action => :edit  
  end  
  
  def edit; end  
  
end  
 
你还可以使用 :if(或者 :unless) 来传递一个 指定何时应缓存 action 的 Proc。此外,你还可以使用 :layout=> false 使缓存没有布局,这样以来布局模板中的动态信息比如已经登录的用户的用户名或者是购物车中商品的数量可以被保留。使用这项功能需要Rails2.2及更高 版本。
 
你可以传递一个:cache_option选项来修改默认的缓存路径。这会直接传递给 ActionCachePath.path_for 。这对于有多个可用路由并且需要做不同缓存的情况非常有用。如果指定了一个代码块,那么他将被当前控制器实例所调用。
 
最后,如果你在使用 memcache,你还可以传递 :expires_in 。事实上,所以 caches_action 没用到的参数都会被发送给底层缓存存储。
 
1.3 片断缓存 Fragment Caching
 
如果我们只需要把一个页面或者一个action的内容缓存起来然后发给用户那该多好。不幸的是,动态web应用通常都由很多个部份组成,他们具有不 同的页面特征。为了解决此类的动态创建的页面,在页面的不同部份需要建立不同的缓存和缓存失效机制。Rails提供了一种叫片断缓存的东西来解决这个问 题。
 
片断缓存允许视图逻辑的一个被缓存块包裹起来的片断形成一个缓存,在下次受到请求的时候发送出去。
 
举个例子,如果你想即时的显示你的网站中的全部订单并且不想在那个部份使用缓存,但是想缓存页面上列出全部商品的列表,你可以使用这段代码:
 
Ruby代码 
<% Order.find_recent.each do |o| %>  
  <%= o.buyer.name %> bought <% o.product.name %>  
<% end %>  
  
<% cache do %>  
  All available products:  
  <% Product.find(:all).each do |p| %>  
    <%= link_to p.name, product_url(p) %>  
  <% end %>  
<% end %>  
 
我们示例中的缓存块将绑定到调用他的那个action并且和acion缓存放在相同的路径下。这意味着如果你的每个action中有多个缓存片断,你就应当为cache调用提供一个 action_suffix
 
Ruby代码 
<% cache(:action => 'recent', :action_suffix => 'all_prods') do %>  
  All available products:  
<% Product.find(:all).each do |p| %>  
    <%= link_to p.name, product_url(p) %>  
  <% end %>  
<% end %>  
你可以使用expire_fragment 来使缓存过期:
 
Ruby代码 
expire_fragment(:controller => 'products', :action => 'recent',   :action_suffix => 'all_prods  
 
如果你不希望缓存块绑定到调用它的那个action,也可以使用全局标示片段。像这样,通过一个键来调用缓存方法:
 
Ruby代码 
<% cache(:key => ['all_available_products', @latest_product.created_at].join(':')) do %>  
  All available products:  
<% end %>  
 
这个片段就可以在Products控制器的所有actions中使用键来调用并且使用相同的方法来使之失效:
 
Ruby代码 
expire_fragment(:key => ['all_available_products', @latest_product.created_at].join(':'))  
 
1.4  扫地大妈 Sweepers
 
缓存扫地大妈 是一种允许你把代码中的一大堆 expire_{page,action.fragment}调用放在一起的机制。这是通过把所有的清除缓存内容的工作都移动到 ActionController::Cacheing::Sweeper 类种来实现的。这个类是一个通过回调监控一个对象状态改变的监视器。当发生改变的时候,他就通过那个对象的前后过滤器或后置过滤器来让那个对象的缓存失 效。
 
继续我们的Product控制器示例,我们可以像这样通过sweeper来重写他:
 
Ruby代码 
class StoreSweeper < ActionController::Caching::Sweeper  
  # This sweeper is going to keep an eye on the Product model  
  observe Product  
  
  # If our sweeper detects that a Product was created call this  
  def after_create(product)  
          expire_cache_for(product)  
  end  
  
  # If our sweeper detects that a Product was updated call this  
  def after_update(product)  
          expire_cache_for(product)  
  end  
  
  # If our sweeper detects that a Product was deleted call this  
  def after_destroy(product)  
          expire_cache_for(product)  
  end  
  
  private  
  def expire_cache_for(record)  
    # Expire the list page now that we added a new product  
    expire_page(:controller => '#{record}', :action => 'list')  
  
    # Expire a fragment  
    expire_fragment(:controller => '#{record}',   
      :action => 'recent', :action_suffix => 'all_products')  
  end  
end  
 
The sweeper has to be added to the controller that will use it. So, if we wanted to expire the cached content for the list and edit actions when the create action was called, we could do the following:
 
扫地大妈已经被添加到那些会用到他的控制器中。所以,如果我们想要在create action 被调用的时候,清除list 和 edit 两个action的缓存内容,我们可以这样做:
 
Ruby代码 
class ProductsController < ActionController  
  
  before_filter :authenticate, :only => [ :edit, :create ]  
  caches_page :list  
  caches_action :edit  
  cache_sweeper :store_sweeper, :only => [ :create ]  
  
  def list; end  
  
  def create  
    expire_page :action => :list  
    expire_action :action => :edit  
  end  
  
  def edit; end  
  
end  
 
1.5 SQL缓存   SQL Caching
 
查询缓存是一个对每个查询返回的数据集进行缓存的一个Rails特色。如果Rails在本次请求种再次发起了相同的查询,他就会使用被缓存起来的结果集而不需要再次对数据库发出请求。
 
Ruby代码 
class ProductsController < ActionController  
  
  before_filter :authenticate, :only => [ :edit, :create ]  
  caches_page :list  
  caches_action :edit  
  cache_sweeper :store_sweeper, :only => [ :create ]  
  
  def list  
    # Run a find query  
    Product.find(:all)  
  
    ...  
  
    # Run the same query again  
    Product.find(:all)  
  end  
  
  def create  
    expire_page :action => :list  
    expire_action :action => :edit  
  end  
  
  def edit; end  
  
end  
 
在上面的list 这个action,Product.find(:all)返回的结果会被缓存起来,下次再发起这个finder调用的时候就不需要再次读取数据库了。
 
1.6  缓存存储 Cache Stores
 
Rails 提供为action 缓存 和 片段缓存的数据提供很不同的存储方法。页面缓存通常是被存在磁盘上的。
 
Rails2.1 以及更新版本提供了可以缓存字符串的 ActiveSupport::Cache::Store 。一些像MemoryStore的缓存存储可以缓存任意的Ruby对象,但不要指望每个缓存存储都可以这样做。
 
钢轨 2.1 和以上提供 ActiveSupport::Cache::Store,可用于缓存的字符串。 一些缓存存储像 MemoryStore 的实现,能够缓存任意的 Ruby 对象,但不要指望能够这样做的每个缓存存储区。
 
默认的Rails包含的缓存存储提供了:
 
1) ActiveSupport::Cache::MemoryStore:一种用相同进程把所有的东西存储到内存中的缓存存储实现。如果你运行了多个 Ruby on Rails服务进程(比如 你在同时使用 mongrel_cluser 或者 Phusion Passenger),然后这意味着你的Rails服务进程实例不能够彼此共享缓存数据。如果你的应用不执行手动的缓存失效(如比你用缓存键),然后使用 MemoryStore是可以的。否则,仔细考虑是否您应该使用此缓存存储。
 
MemoryStoreis 不仅仅可以存储字符串,而且也可以存储任意Ruby对象。MemoryStoreis不是安全线程。如果你需要安全线程,请改用SynchronizedMemoryStore 的内容。
 
Ruby代码 
ActionController::Base.cache_store = :memory_store  
 
2) ActiveSupport::Cache::FileStore:缓存数据存放在磁盘上。这个默认的存储,路径是/tmp/cache. 在所有的环境下都工作得很好,并且允许所有的线程从相同应用程序文件夹中访问缓存内容。如果/tmp/cache不存在,那么默认的存储方式变成 memoryStore.
 
Ruby代码 
ActionController::Base.cache_store = :file_store, "/path/to/cache/directory"  
 
3) ActiveSupport::Cache::DRbStore: 缓存的数据存储在一个所有服务可以与之通信的单独的共享DRb进程中。这适用于所有环境,并为所有进程保持一个缓存。但是这就要求你运行并管理一个单独的DRb线程。
 
Ruby代码 
ActionController::Base.cache_store = :drb_store, "druby://localhost:9192"  
 
4) MemCached store: Works like DRbStore, but uses Danga’s MemCache instead. Rails uses the bundled memcached-client gem by default. This is currently the most popular cache store for production websites.
 
4) MemCached store:
 
未完---待续
 

rails cache managment

Rails 自身提供四种缓存方式,即 Page Cache, Action Cache,Fragment Cache 和 ActiveRecord Cache 这三种缓存。Page Cache 是最高效的缓存机制,他把整个页面以静态页面 HTML 的形式进行缓存,这对于不会经常发生变化的页面是非常有效的。Action Cache 是对某个 action 进行缓存,与 Page Cache 的区别在于:HTTP 请求会经过 Rails 应用服务器,直到所有的 before filters 都被处理,这种缓存就能处理 Page Cache 无法处理的如需要登录验证的页面,可以所验证的步骤加入 before filter 中,Fragment Cache 则为了缓存页面中的某一部分,同一个页面中的不同部分还可以采用不同的过期策略。对于 Rails 本身的缓存机制,我们可以写 sweeper 进行过期和清除的处理。ActiveRecord Cache 则是较新版本 Rails 中新推出的对 ActiveRecord 的缓存机制,使用 SQL 查询缓存,对于同一 action 里面同一 SQL 语句的数据库操作会使用缓存。

Rails 的缓存机制能非常有效的提升网站性能,Rails 默认是将缓存存在于文件系统中,这并不是适合生产环境下的存储方式,文件 IO 的效率有限,Rails 还支持在同一进程的内存中保存 Cache,但如果有多个 Rails application,它们之间不能共享缓存。我们这里推荐的是以 MemCached 的方式进行存储,这也是目前是流行的缓存存储方式。

Memcached 是由 Danga Interactive 开发,用于提升 LiveJournal.com 访问速度的。LiveJournal.com 每秒有几千次动态页面访问量,用户 700 万。Memcached 是一个具有极高性能的分布式内存对象缓存系统 , 基于一个存储键 / 值对的哈希表。其守护进程(daemon)是用 C 写的 , Memcached 将数据库负载大幅度降低,更好的分配资源,更快速访问。可以用各种其它语言去实现客户端。上文的介绍中已经安装了 Rails 的 Memcached 客户端,因为我们只需要在 Rails 应用程序中做如下配置:

				 
 config.cache_store = :mem_cache_store, 'localhost:11211'

便可以进行使用 MemCached 进行缓存数据。除了 Rails 本身的缓存机制,我们还直接用 Rails.cache 操作 Memcached 进行数据缓存,如,我们读取所有 blog 的数量,可以如下使用缓存:

				 
 blogs_count = Rails.cache.fetch("blogs_count") do 
    Blog.count 
 end 

Rails 自身的 ActiveRecord 作用有限,只适用同一个 action 中的 SQL 查询语句进行缓存,我们需要一个更强大的 ActiveRecord 缓存,而 cache-money 更是为了解决如此问题而推出的。当 twitter 网站变得越来越稳定,逐渐摆脱被人拿来作为"Rails 无法扩展的"典型例子的阴影时,人们便期待 twitter 开发团队能向 Rails 社区有更多的贡献,cache-money 便是在 Starling 之后 twitter 团队贡献出来的另一个插件。cache-money 和 Hibernate 的二级缓存类似,是一个读写式(write-through)缓存。在 ActiveRecord 对象更新的时候不是将缓存中的数据清除,而是直接将更新的内容写入到缓存中去。

cache-money 有许多很棒的特性,如:缓存自动清除机制 ( 利用 after_save/after_destroy) ;支持事务,由于 Rails 的 Active Record 没有提供 after_commit 机制,目前常见的缓存插件在高并发下会出现缓存更新竞争冲突,而这个特性对于解决这个问题会很有帮助,可以通过 gem 来安装 cache-money:

				 
 gem sources -a http://gems.github.com 
 sudo gem install nkallen-cache-money 
 require 'cache_money'

 

				 
 production: 
  ttl: 604800 
  namespace: ... 
  sessions: false 
  debug: false 
  servers: localhost:11211 

 development: 
   .... 

 

				 
 config = YAML.load(IO.read(File.join(Rails_ROOT, "config", "Memcached.yml")))[Rails_ENV] 
 $memcache = MemCache.new(config) 
 $memcache.servers = config['servers'] 
 $local = Cash::Local.new($memcache) 
 $lock = Cash::Lock.new($memcache) 
 $cache = Cash::Transactional.new($local, $lock) 
 class ActiveRecord::Base 
  is_cached :repository => $cache 
 end 

使用 cache-money 非常方便,不需要额外的操作,只需要在你的 Model 里面进行简单的配置,如:

				 
 class User < ActiveRecord::Base 
  index :name 
 end 
 class Post < ActiveRecord::Base 
  index [:title, :author] 
 end 
 class Article < ActiveRecord::Base 
  version 7 
  index ... 
 end 

然后便可以跟以前一样使用 Rails ActiveRecord 各种方法以及事务操作。如果你改变了数据库的表结构,你可以改变 Model 的版本号来使以前的缓存失效,而不需要重启 Memcached 服务器。

 

****************************

 

选用 Session 容器

Rails 提供了几个内建的 Session 容器。在所有我分析过的应用程序里,要么使用了将 Session 信息储存在你文件系统上独立文件的 PStore,要么用了和数据库打交道的 ActiveRecordStore。这两个方案都不甚理想,特别是拖累了缓存 Action 的页面(action cached pages)。这里提供两个好用得多的备选方案供大家参考:SQLSessionStore 和 MemCacheStore

SQLSessionStore 通过以下手段避免了 ActiveRecordStore 相关的额外性能开支:

  • 避免使用事务(对于 SQLSessionStore 的正确操作,它们并不是必要的)
  • 撤销向数据库更新“created_at”和“updated_at”的操作

如果使用 MySQL,你应当保证使用 MyISAM 表来存储 Session 数据,因为它要比 InnoDB 表快很多,并且它不会强制你使用事务处理。前不久我又为 SQLSessionStore 增加了 Postgres 支持,不过,用于 Session 存储 Postgres 看起来要比 MySQL 慢得多。因此,如果你打算使用基于数据库的 Session 存储,我推荐为 Session 表安装 MySQL 数据库(我想不出一个基于 session id 的需要连接的更好用例(use case))。

MemCacheStore 要比 SQLSessionStore快得更多。我的测评结果显示,对于缓存了 Action 的页面它能够带来了 30% 的速度提升 。你得先安装 Eric Hodel 的 memcache client ,并在 environment.rb 中做相应配置之后才能正常使用。注意:Ruby-Memcache 还是不要去试的好(实在、实在慢得让人难以忍受)。

在我自己的项目中,我更倾向于使用基于数据库的 Session 存储,原因是可以使用 Rails 命令行或者数据库软件包提供的管理工具进行简单得管理。对于 MemCacheStore 你就得自己为它编写脚本了。另一方面,对于高访问量网站来说,内存缓存方式的扩展性更好一些,并且它随支持 Session 超时(session expiry)的 Rails 一起提供。

 

 

Session优化
如果你的系统需要为每个访问者保存单独的Session信息(比如购物网站),那么session的存取速度将是影响系统性能的关键因素,目前可用的session存取策略有:
内存,快,相当快!但是如果你的应用挂了,或者由于其它什么原因需要重启,那么所有的session信息都会丢失,并且这种方式仅仅只能在单APP Server的应用中使用
文件系统,很容易使用,每个session对应一个文件,并且可以通过NFS或者NAS轻松进行容量扩展,但是速度较慢
数据库/ActiveRecordStore,使用简单(Rails的默认策略),但是很慢
数据库/SQLSessionStore,与上面一种方式类似,但是使用原始SQL取代了ActiveRecord,性能有一定提升,关于SQLSessionStore与ActiveRecordStore的对比可以参看这篇文章
memcached,比SQLSessionStore稍微快一些,可扩展性较好,但是较难获取统计信息,关于memcached与SQLSessionStore的对比,请参看这篇文章
DrbStore,在memcached不支持的一些平台上,可以选择DrbStore,但是性能比memcached要差一些,并且不支持session自动清除。
 
 

Nautilus Tips and Tricks

Managing Nautilus from the keyboard

You don’t have to be slowed down by the mouse just because you are using a GUI. Nautilus has great keyboard shortcuts that will allow you to use it quickly and effectively.

Here is a quick table of the shortcut keys and their functionality

Key(s) Action
Searching
Start Typing Select the matching name of a file or directory
CTRL+F Search filenames and content of indexed files
CTRL+S Selects all files or directories matching a pattern
Display and Window Management
CTRL+N Create a new Nautilus window
CTRL+W Close a Nautilus window
CTRL+SHIFT+W Close all Nautilus windows
CTRL+1 View files in icon mode
CTRL+2 View files in list mode
F9 Toggle sidebar pane
File Management
CTRL+H Show hidden files
CTRL+SHIFT+N Create a new folder
CTRL+T or Del Delete the file or directory and move to the trash
Shift+Del Delete the selected file or directory and skip the trash
F2 Rename the selected file or directory
Alt+Enter View properties of the selected file or directory
Movement
CTRL+L Move into the location bar
Alt+HOME Go to your $HOME folder
* or + or SHIFT+RArrow Expand Directory in list view
- or SHIFT+LArrow Close Directory in list view
ALT+LArrow Browse through files and folders to the left
ALT+RArrow Browse through files and folders to the right
ALT+UArrow Move to the parent folder one level above
ALT+DArrow Open the selected file or folder
Accessibility
CTRL++ Zoom in
CTRL+- Zoom out
CTRL+0 Normal zoom

 

-->>from http://opensuse-tutorials.com/2008/07/nautilus-tips-and-tricks/

Ubuntu关联site集(J)

Ubuntuを紹介しているBlog等

  • Ubuntuウィークリーニュースレター (RSS)

    • Ubuntuウィークリーニュースレター(Ubuntu Weekly Newsletter, UWN) - 今週のUbuntu・Kubuntu・Edubuntu・Xubuntuの全ての活動をレポートします。
    • 日本語への翻訳協力者募集中です。(詳細)

  • Ubuntu Weekly Topics (RSS)

    • Ubuntuコミュニティに興味があるユーザ向けに,ML・Wiki・フォーラムなどの最新の話題を1週間分厳選してお届けします。基本的に毎週金曜日に更新されます。Ubuntu Japanese Team 提供です。
  • Ubuntu Weekly Recipe

    • Ubuntuの強力なデスクトップ機能を活用するための,いろいろなレシピをお届けします。基本的に毎週水曜日に更新されます。Ubuntu Japanese Team 提供です。
  • 行っとけ! Ubuntu道場!

    • Ubuntuの今をフレンドリーに座談会形式で解説。基本的に隔週木曜日に更新されます。Ubuntu Japanese Team 提供です。
  • Full Circle Magazine (RSS)

    • Full Circle is a free, independent, magazine dedicated to the Ubuntu family of Linux operating systems. Each month, it contains helpful how-to articles and reader submitted stories.
    • 月刊のフリーUbuntu雑誌です。面白い読み物と役に立つHowToが充実しています。

    • 日本語への翻訳協力者募集中です。
  • Tutorial of the Week

    • 英語フォーラムに寄せられたTipsのうち秀逸なものを毎週1つずつ紹介しています。
    • 日本語への翻訳協力者募集中です。(詳細)

  • Viva! Ubuntu!! (RSS)

    • 極力コマンドラインを使わない、直感的な Ubuntu の利用・紹介記事が充実。u-bon氏による。
  • Ubuntuのある日々 (RSS)

    • ふつうの人のふつうのLinux の著者によるブログ。
  • 独学Linux (RSS)

    • Ubuntuに限らず、デスクトップ用途での Linux 利用記事が充実しています。Compiz関連情報も。vine_user 氏による。

  • Linux Salsad (RSS)

    • エントリ中に"メチャな女の子やクールな女性や若い奥様に向けてLinuxやUbuntuの話題を書いているブログ"と執筆者のコメントがあるように、ポップな雰囲気で分かりやすい。Akira Ohgaki 氏による。

  • うぶんちゅ! (RSS)

    • 「世界初!? 学園Ubuntuラブコメ」
    • 第一話が有志の手により現時点で日本語を含め17ヵ国語で読めるようになっているとのこと。Cc-By-Nc-2.1-jpで公開されている。瀬尾浩史 氏による。

  • ubuntu smash (RSS)

  • たわごと (RSS)

  • Kawaji's Weblog (RSS)

    • Kawaji さんによるブログ
  • ひよこのグダグダUbuntu日記 (Atom)

  • ubulog (Atom)

    • ubuntuとEmacsに関する記述が多いです。
  • Ubuntu Blog Network

    • ユウヤ さんが運営していて、情報を発信するUbuntuブロガーと、情報を探しているUbuntuユーザの架け橋を目指しているそうです。

  • Winux/Lindows (RSS)

    • tmin さんによるブログです。

 

ソフトウェア関連

  • リリースノート

    • 公式のリリースノートです。各バージョンのUbuntuのリリース時点における既知の不具合の情報が記載されているます。日本語訳はこちらを参照のこと。

  • Official Ubuntu Documentation

    • 公式 Ubuntu 関連ドキュメントサイトです。"Ubuntu Documentation Project Team"による。システム ▶ ヘルプとサポート (yelp) から閲覧できます。

  • Ubuntu Manpages

    • 通常コマンド"man"で利用するマニュアルページがブラウザ上から利用出来る。Ubuntu公式です。
  • Launchpad’s bug tracker

    • 公式のバグトラッカーです。バグに遭遇した際の解決策の検索に有用です。
  • Community Ubuntu Documentation

    • コミュニティにより保守されているドキュメントです。
  • ubuntu guide

    • 有志による Ubuntuの利用ガイド。
    • 日本語への翻訳協力者募集中。
  • Ubuntu Packages Search

    • 公式のパッケージ検索サイトです。検索機能に特化しています。
  • Appnr

    • "Web-based package browser"
    • apturlを利用しており、ブラウザ上からアプリケーションの検索とインストールが行える。Akira Ohgaki氏による。

  • Personal Package Archives

  • Medibuntu

    • 公式リポジトリでは配布の難しいソフトを配布。
    • サードパーティのレポジトリを利用した場合アップグレード時に特別な操作が必要となる場合あり。
    • 利用しようとするソフトが目的の用途で国内法的に問題ないことを確認して利用のこと。
    • 日本語Wikiにおける利用方法の紹介

  • GetDeb

    • まだリポジトリで提供されていない、リポジトリにあるものは最新ではない、といったソフトウェアのパッケージを大量に配布。
    • 公式リポジトリ外のパッケージの導入はシステムにセキュリティ上のリスク、アップグレードの際のリスク、運用上の予期せぬ不具合の可能性を与えることを認識の上利用のこと。
  • UbuntuTweak

    • Windowsにおける「窓の手」に類似したソフト"ubuntu-tweak"の開発と配布。
    • 公式リポジトリ外のパッケージの導入はシステムにセキュリティ上のリスク、アップグレードの際のリスク、運用上の予期せぬ不具合の可能性を与えることを認識の上利用のこと。
  • Ubuntu Security Notice (RSS)

    • Ubuntu のセキュリティアップデートに関する情報があります。日本語訳は Ubuntu Weekly Topics の今週のセキュリティアップデートにあります。

 

Linux 全般に関する情報

 

ハードウェア関連

  • Phoronix

    • Linux のハードウェアレビューが充実しています。Phoronix Mediaが提供しています。

-->>from https://wiki.ubuntulinux.jp/UbuntuSites

 

todo list

 

Comparing Open Source Reporting Tools for Use in the Enterprise
 

http://olex.openlogic.com/wazi/2008/open-source-reporting-tool-comparison-for-the-enterprise/

How to Integrate JasperReports with Ruby on Rails

http://wiki.rubyonrails.org/rails/pages/howtointegratejasperreports

 

SED&AWK学习资料

http://www.bathome.net/thread-1929-1-1.html

facebook是如何管理代码的

 

原文在此,看完之后,终于明白为什么优秀的工程师都去了/想去facebook,因为那里是工程师们的天堂。

译文:

我对facebook的运转着迷。这是一个很独特的环境,不容易被复制(他们的体系并不适合所有的公司,即使他们努力尝试过)。下面是我和facebook的朋友们关于他们如何开发和管理项目的记录。

现在距离我收集的这些信息又过去6个月了,我相信facebook肯定又对他们的项目开发实践进行了改进。所以这些记录可能会有点过时。同时facebook的工程师驱动文化也越来越为大众所知。非常感谢那些帮助我整理这篇文章的facebook的朋友们。

记录:

  • 截止到2010年6月,facebook有将近2000名员工,10个月前只有1100名,一年之间差不多翻了一番。
  • 两个最大的部门是工程师和运维,每个部门大概都是400-500人。这两个部门人数大约占了公司的一半。
  • 产品经理与工程师的比例大约为1-7到1-10。
  • 每个工程师入职时,都要接收4-6周的培训,通过修补bugs和听高级开发工程师的课程来熟悉facebook。
  • 培训结束后,每个工程师都可以接触线上的数据库(更大的权力意味着更大的责任,也有一份"勿做清单",不然可能会被开,比如共享用户的隐私数据)。
  • 有非常牢靠的安全体系,以免有人不小心/故意做了些不好的事。
  • 每个工程师可以修改facebook的任何代码,随时可以迁入。
  • 浓厚的工程师驱动文化。"产品经理基本可以被忽略",这是facebook一名员工的话。工程师可以修改流程的细节,重新安排工作任务,随时植入自己的想法。
  • 在每月的跨部门会议上,由工程师来汇报工作进度,市场部和产品经理会出席会议,也可以做些简短的发言,但如果说得太多,很可能就会被打小报告。他们确实想让工程师来主导产品的开发,对自己的产品负责。
  • 项目需要的资源都是自愿的
    • 一个产品经理把工程师们召集到一起,让他们对他的想法产生兴趣。
    • 工程师们决定开发那些让他们感兴趣的特性。
    • 工程师跟他们的经理说:"我下周想开发这5个新特性"。
    • 经理会让工程师独立开发,可能有时会让他优先完成一些特性。
    • 工程师独立完成所有的特性——前端/后端/数据库,等等所有相关的部分。如果需要得到设计人员的帮助,需要先让设计人员对你的想法产生兴趣。其他如架构之类的也一样。但总体来说,工程师要独立完成所有的任务。
  • 对于某个特性是否值得开发的争论,通常是这么解决的:花一个星期的时间完成他,并在小部分人群中(如1%)进行测试。
  • 工程师常常希望解决难题,这能获得声望和尊敬。他们很难对前端项目或UI设计产生太大的兴趣。这跟其他公司可能正好相反。在facebook,后端任务,比如新的feed算法,广告投放算法,memcache优化等等,是工程师真正感兴趣的。
  • 所有的代码修改都要进行审核(通过一个或多个工程师),但News Feed是个例外,因为太重要了,Zuckerberg会亲自review。
  • 所有的修改至少要被一个人审核,而且这个系统可以让任何人很方便地审核其他人的代码,即使你没有邀请他
  • 工程师负责测试,代码修复,和维护自己的项目。
  • 每个办公室或通过VPN连接的员工会使用下一版的facebook,这个版本的facebook会经常更新,通常比公开的早1-12小时。所有的员工被强烈建议提交bugs,而且通常会很快被修复。
  • 很奇怪只有很少的QA或自动测试——"大部分工程师都能写出基本没有bug的代码,只是在其他公司他们不需要这么做。如果有QA部门,他们只要把代码写完,扔给他们就行了"
  • [针对上一条]我们有自动测试,代码发布前必须要通过测试。我们不相信"所有的工程师都能写出没有bug的代码",毕竟这是一个商业公司。
  • 很奇怪,缺少产品经理的影响和控制——产品经理是很独立的和自由的。产生影响力的关键是与工程师和工程师的领导们们搞好关系。需要大致了解技术,不要提一些愚蠢的想法。
  • 所有提交的代码每周二打包一次。
  • 只要多一分努力,终于一天会发生改变。
  • 星期二的代码发布,需要所有的提交过代码的工程师在场。
  • 代码打包前,工程师必须在一个特殊的IRC channel上。
  • 运维执行打包过程
    • facebook有大约60000台服务器
    • 有9个代码发布级别
    • 最小的级别只有6台服务器
    • 星期二的代码发布会先发布到6台服务器上,运维组会检测这6台服务器的反应,保证代码正常工作,然后再提交到下一级
    • 如果发布出现了一些问题(如报错等等),那么就停止下一级的部署,提交出错代码的工程师负责修复问题,然后从头继续发布。
    • 所以一次发布可能会经历几次重复:1-2-3-fix. 回到1. 1-2-3-4-5-fix. 回到1. 1-2-3-4-5-6-7-8-9
  • 运维组是受过严格训练,倍受尊敬,而且有商业意识的。他们的工作包括分析错误日志,负载和内存状态等等。还包括用户行为。
  • 代码发布期间,运维组使用IRC-based页面系统,可以通过facebook/email/irc/im/sms ping每一个工程师,如果需要他们注意的话。对运维组不做回应是一件很羞愧的事。
  • 代码一旦发布到第9级,并且稳定运行,就算发布成功了。
  • 如果一个特性没有按时完成,也没什么大不了的,下次完成时一并发布即可。
  • 如果被svn-blamed,public shamed或工作经常疏忽就很可能被开除。"这是一个高效的文化"。不够高效或者不够聪明的员工会被剔除。管理层会在6个月的时间里观察你表现,如果不合格,只能说再见。每一级都是这个待遇,即使是C级别和VP级别,如果不够高效,也会被开除。
  • 被责骂不会导致解雇。我们特别尊重别人,原谅别人。大部分高级工程师都或多或少犯过一些严重的错误,包括我。但没有人因此被解雇。
  • 我也没有遇到过因为上面提到过的犯错误而被解雇。有些人犯了错,他们会非常努力地去修复,也让其他人得到了学习。

--EOF--

-->>转自 http://blog.leezhong.com/

UNIX 高手的 20 个习惯

 

不良的使用模式会降低您的速度,并且通常会导致意外错误。养成这些好习惯是加强您的 UNIX 命令行技能的积极步骤。

 

Unix 下要采用的20个好习惯为:

1)        在单个命令中创建目录树。

2)        更改路径;不要移动存档。

3)        将命令与控制操作符组合使用。

4)        谨慎引用变量。

5)        使用转义序列来管理较长的输入。

6)        在列表中对命令分组。

7)        在 find 之外使用 xargs 。

8)        了解何时 grep 应该执行计数——何时应该绕过。

9)        匹配输出中的某些字段,而不只是对行进行匹配。

10)    停止对 cat 使用管道。

11)    使用文件名自动完成功能 (file name completion)。

12)    使用历史扩展。

13)    重用以前的参数。

14)    使用 pushd 和 popd 管理目录导航。

15)    查找大型文件。

16)    不使用编辑器创建临时文件。

17)    使用 curl 命令行实用工具。

18)    最有效地利用正则表达式。

19)    确定当前用户。

20)    使用 awk 处理数据。

 

1. 在单个命令中创建目录树

清单 1 演示了最常见的 UNIX 坏习惯之一:一次定义一个目录树。

 

清单 1. 坏习惯 1 的示例:单独定义每个目录树

~ $ mkdir tmp

~ $ cd tmp

~/tmp $ mkdir a

~/tmp $ cd a

~/tmp/a $ mkdir b

~/tmp/a $ cd b

~/tmp/a/b/ $ mkdir c

~/tmp/a/b/ $ cd c

~/tmp/a/b/c $

 

       使用 mkdir 的 -p 选项并在单个命令中创建所有父目录及其子目录要容易得多。但是即使对于知道此选项的管理员,他们在命令行上创建子目录时也仍然束缚于逐步创建每级子目录。花时间有意识地养成这个好习惯是值得的.


 清单 2. 好习惯 1 的示例:使用一个命令来定义目录树

~ $ mkdir -p tmp/a/b/c

 

       您可以使用此选项来创建整个复杂的目录树(在脚本中使用是非常理想的),而不只是创建简单的层次结构。


 清单 3. 好习惯 1 的另一个示例:使用一个命令来定义复杂的目录树

~ $ mkdir -p project/{lib/ext,bin,src,doc/{html,info,pdf},demo/stat/a}

 

       过去,单独定义目录的唯一借口是您的 mkdir 实现不支持此选项,但是在大多数系统上不再是这样了。IBM、AIX®、mkdir、GNU mkdir 和其他遵守单一 UNIX 规范 (Single UNIX Specification) 的系统现在都具有此选项。

       对于仍然缺乏该功能的少数系统,您可以使用 mkdirhier 脚本(请参见参考资料),此脚本是执行相同功能的 mkdir 的包装:

~ $ mkdirhier project/{lib/ext,bin,src,doc/{html,info,pdf},demo/stat/a}

 

2. 更改路径;不要移动存档

       另一个不良的使用模式是将 .tar 存档文件移动到某个目录,因为该目录恰好是您希望在其中提取 .tar 文件的目录。其实您根本不需要这样做。您可以随心所欲地将任何 .tar 存档文件解压缩到任何目录——这就是 -C 选项的用途。在解压缩某个存档文件时,使用 -C 选项来指定要在其中解压缩该文件的目录:


清单 4. 好习惯 2 的示例:使用选项 -C 来解压缩 .tar 存档文件

~ $ tar xvf -C tmp/a/b/c newarc.tar.gz

 

       相对于将存档文件移动到您希望在其中解压缩它的位置,切换到该目录,然后才解压缩它,养成使用 -C 的习惯则更加可取——当存档文件位于其他某个位置时尤其如此。

 

3. 将命令与控制操作符组合使用

       您可能已经知道,在大多数 Shell 中,您可以在单个命令行上通过在命令之间放置一个分号 (;) 来组合命令。该分号是 Shell 控制操作符,虽然它对于在单个命令行上将离散的命令串联起来很有用,但它并不适用于所有情况。例如,假设您使用分号来组合两个命令,其中第二个命令的正确执行完全依赖于第一个命令的成功完成。如果第一个命令未按您预期的那样退出,第二个命令仍然会运行——结果会导致失败。相反,应该使用更适当的控制操作符(本文将描述其中的部分操作符)。只要您的 Shell 支持它们,就值得养成使用它们的习惯。

 

3.1 仅当另一个命令返回零退出状态时才运行某个命令

       使用 && 控制操作符来组合两个命令,以便仅当 第一个命令返回零退出状态时才运行第二个命令。换句话说,如果第一个命令运行成功,则第二个命令将运行。如果第一个命令失败,则第二个命令根本就不运行。例如:


清单 5. 好习惯 3 的示例:将命令与控制操作符组合使用

~ $ cd tmp/a/b/c && tar xvf ~/archive.tar

 

       在此例中,存档的内容将提取到 ~/tmp/a/b/c 目录中,除非该目录不存在。如果该目录不存在,则 tar 命令不会运行,因此不会提取任何内容。

 

3.2 仅当另一个命令返回非零退出状态时才运行某个命令

       类似地,|| 控制操作符分隔两个命令,并且仅当第一个命令返回非零退出状态时才运行第二个命令。换句话说,如果第一个命令成功,则第二个命令不会运行。如果第一个命令失败,则第二个命令才会 运行。在测试某个给定目录是否存在时,通常使用此操作符,如果该目录不存在,则创建它:


清单 6. 好习惯 3 的另一个示例:将命令与控制操作符组合使用

~ $ cd tmp/a/b/c || mkdir -p tmp/a/b/c

 

       您还可以组合使用本部分中描述的控制操作符。每个操作符都影响最后的命令运行:


清单 7. 好习惯 3 的组合示例:将命令与控制操作符组合使用

~ $ cd tmp/a/b/c || mkdir -p tmp/a/b/c && tar xvf -C tmp/a/b/c ~/archive.tar

 

 

4. 谨慎引用变量

       始终要谨慎使用 Shell 扩展和变量名称。一般最好将变量调用包括在双引号中,除非您有不这样做的足够理由。类似地,如果您直接在字母数字文本后面使用变量名称,则还要确保将该变量名称包括在方括号 ([]) 中,以使其与周围的文本区分开来。否则,Shell 将把尾随文本解释为变量名称的一部分——并且很可能返回一个空值。清单 8 提供了变量的各种引用和非引用及其影响的示例。


清单 8. 好习惯 4 的示例:引用(和非引用)变量

~ $ ls tmp/

a b

~ $ VAR="tmp/*"

~ $ echo $VAR

tmp/a tmp/b

~ $ echo "$VAR"

tmp/*

~ $ echo $VARa

~ $ echo "$VARa"

~ $ echo "${VAR}a"

tmp/*a

~ $ echo ${VAR}a

tmp/a

~ $

 

5. 使用转义序列来管理较长的输入

       您或许看到过使用反斜杠 (\) 来将较长的行延续到下一行的代码示例,并且您知道大多数 Shell 都将您通过反斜杠联接的后续行上键入的内容视为单个长行。然而,您可能没有在命令行中像通常那样利用此功能。如果您的终端无法正确处理多行回绕,或者您的命令行比通常小(例如在提示符下有长路经的时候),反斜杠就特别有用。反斜杠对于了解键入的长输入行的含义也非常有用,如以下示例所示:


清单 9. 好习惯 5 的示例:将反斜杠用于长输入

~ $ cd tmp/a/b/c || \

> mkdir -p tmp/a/b/c && \

> tar xvf -C tmp/a/b/c ~/archive.tar

 

或者,也可以使用以下配置:
清单 10. 好习惯 5 的替代示例:将反斜杠用于长输入

~ $ cd tmp/a/b/c \

>                 || \

> mkdir -p tmp/a/b/c \

>                    && \

> tar xvf -C tmp/a/b/c ~/archive.tar

 

       然而,当您将输入行划分到多行上时,Shell 始终将其视为单个连续的行,因为它总是删除所有反斜杠和额外的空格。

       注意:在大多数 Shell 中,当您按向上箭头键时,整个多行输入将重绘到单个长输入行上。

 

6. 在列表中对命令分组

       大多数 Shell 都具有在列表中对命令分组的方法,以便您能将它们的合计输出向下传递到某个管道,或者将其任何部分或全部流重定向到相同的地方。您一般可以通过在某个 Subshell 中运行一个命令列表或通过在当前 Shell 中运行一个命令列表来实现此目的。

 

6.1 在 Subshell 中运行命令列表

       使用括号将命令列表包括在单个组中。这样做将在一个新的 Subshell 中运行命令,并允许您重定向或收集整组命令的输出,如以下示例所示:


清单 11. 好习惯 6 的示例:在 Subshell 中运行命令列表

~ $ ( cd tmp/a/b/c/ || mkdir -p tmp/a/b/c && \

> VAR=$PWD; cd ~; tar xvf -C $VAR archive.tar ) \

> | mailx admin -S "Archive contents"

 

       在此示例中,该存档的内容将提取到 tmp/a/b/c/ 目录中,同时将分组命令的输出(包括所提取文件的列表)通过邮件发送到地址 admin。

       当您在命令列表中重新定义环境变量,并且您不希望将那些定义应用于当前 Shell 时,使用 Subshell 更可取。

 

6.2 在当前 Shell 中运行命令列表

       将命令列表用大括号 ({}) 括起来,以在当前 Shell 中运行。确保在括号与实际命令之间包括空格,否则 Shell 可能无法正确解释括号。此外,还要确保列表中的最后一个命令以分号结尾,如以下示例所示:


清单 12. 好习惯 6 的另一个示例:在当前 Shell 中运行命令列表

~ $ { cp ${VAR}a . && chown -R guest.guest a && \

> tar cvf newarchive.tar a; } | mailx admin -S "New archive"

 

7. 在 find 之外使用 xargs

       使用 xargs 工具作为筛选器,以充分利用从 find 命令挑选的输出。find 运行通常提供与某些条件匹配的文件列表。此列表被传递到 xargs 上,后者然后使用该文件列表作为参数来运行其他某些有用的命令,如以下示例所示:


清单 13. xargs 工具的经典用法示例

~ $ find some-file-criteria some-file-path | \

> xargs some-great-command-that-needs-filename-arguments

 

       然而,不要将 xargs 仅看作是 find 的辅助工具;它是一个未得到充分利用的工具之一,当您养成使用它的习惯时,将会希望进行所有试验,包括以下用法。

 

7.1 传递空格分隔的列表

       在最简单的调用形式中,xargs 就像一个筛选器,它接受一个列表(每个成员分别在单独的行上)作为输入。该工具将那些成员放置在单个空格分隔的行上:


清单 14. xargs 工具产生的输出示例

~ $ xargs

                a

                b

                c

                 Control-D

a b c

~ $

       您可以发送通过 xargs 来输出文件名的任何工具的输出,以便为其他某些接受文件名作为参数的工具获得参数列表,如以下示例所示:


清单 15. xargs 工具的使用示例

~/tmp $ ls -1 | xargs

December_Report.pdf README a archive.tar mkdirhier.sh

~/tmp $ ls -1 | xargs file

December_Report.pdf: PDF document, version 1.3

README: ASCII text

a: directory

archive.tar: POSIX tar archive

mkdirhier.sh: Bourne shell script text executable

~/tmp $

 

       xargs 命令不只用于传递文件名。您还可以在需要将文本筛选到单个行中的任何时候使用它:


清单 16. 好习惯 7 的示例:使用 xargs 工具来将文本筛选到单个行中

~/tmp $ ls -l | xargs

-rw-r--r-- 7 joe joe 12043 Jan 27 20:36 December_Report.pdf -rw-r--r-- 1 \

root root 238 Dec 03 08:19 README drwxr-xr-x 38 joe joe 354082 Nov 02 \

16:07 a -rw-r--r-- 3 joe joe 5096 Dec 14 14:26 archive.tar -rwxr-xr-x 1 \

joe joe 3239 Sep 30 12:40 mkdirhier.sh

~/tmp $

 

7.2 谨慎使用 xargs

       从技术上讲,使用 xargs 很少遇到麻烦。缺省情况下,文件结束字符串是下划线 (_);如果将该字符作为单个输入参数来发送,则它之后的所有内容将被忽略。为了防止这种情况发生,可以使用 -e 标志,它在不带参数的情况下完全禁用结束字符串。

 

8. 了解何时 grep 应该执行计数——何时应该绕过

       避免通过管道将 grep 发送到 wc -l 来对输出行数计数。grep 的 -c 选项提供了对与特定模式匹配的行的计数,并且一般要比通过管道发送到 wc 更快,如以下示例所示:


清单 17. 好习惯 8 的示例:使用和不使用 grep 的行计数

~ $ time grep and tmp/a/longfile.txt | wc -l

2811

real    0m0.097s

user    0m0.006s

sys     0m0.032s

~ $ time grep -c and tmp/a/longfile.txt

2811

 

real    0m0.013s

user    0m0.006s

sys     0m0.005s

~ $

 

       除了速度因素外,-c 选项还是执行计数的好方法。对于多个文件,带 -c 选项的 grep 返回每个文件的单独计数,每行一个计数,而针对 wc 的管道则提供所有文件的组合总计数。

       然而,不管是否考虑速度,此示例都表明了另一个要避免地常见错误。这些计数方法仅提供包含匹配模式的行数——如果那就是您要查找的结果,这没什么问题。但是在行中具有某个特定模式的多个实例的情况下,这些方法无法为您提供实际匹配实例数量 的真实计数。归根结底,若要对实例计数,您还是要使用 wc 来计数。首先,使用 -o 选项(如果您的版本支持它的话)来运行 grep 命令。此选项仅 输出匹配的模式,每行一个模式,而不输出行本身。但是您不能将它与 -c 选项结合使用,因此要使用 wc -l 来对行计数,如以下示例所示:


清单 18. 好习惯 8 的示例:使用 grep 对模式实例计数

~ $ grep -o and tmp/a/longfile.txt | wc -l

3402

~ $

 

       在此例中,调用 wc 要比第二次调用 grep 并插入一个虚拟模式(例如 grep -c)来对行进行匹配和计数稍快一点。

 

9. 匹配输出中的某些字段,而不只是对行进行匹配

       当您只希望匹配输出行中特定字段 中的模式时,诸如 awk 等工具要优于 grep。

       下面经过简化的示例演示了如何仅列出 12 月修改过的文件。


清单 19. 坏习惯 9 的示例:使用 grep 来查找特定字段中的模式

~/tmp $ ls -l /tmp/a/b/c | grep Dec

-rw-r--r--  7 joe joe  12043 Jan 27 20:36 December_Report.pdf

-rw-r--r--  1 root root  238 Dec 03 08:19 README

-rw-r--r--  3 joe joe   5096 Dec 14 14:26 archive.tar

~/tmp $

 

       在此示例中,grep 对行进行筛选,并输出其修改日期和名称中带 Dec 的所有文件。因此,诸如 December_Report.pdf 等文件是匹配的,即使它自从一月份以来还未修改过。这可能不是您希望的结果。为了匹配特定字段中的模式,最好使用 awk,其中的一个关系运算符对确切的字段进行匹配,如以下示例所示:


清单 20. 好习惯 9 的示例:使用 awk 来查找特定字段中的模式

~/tmp $ ls -l | awk '$6 == "Dec"'

-rw-r--r--  3 joe joe   5096 Dec 14 14:26 archive.tar

-rw-r--r--  1 root root  238 Dec 03 08:19 README

~/tmp $

 

10. 停止对 cat 使用管道

       grep 的一个常见的基本用法错误是通过管道将 cat 的输出发送到 grep 以搜索单个文件的内容。这绝对是不必要的,纯粹是浪费时间,因为诸如 grep 这样的工具接受文件名作为参数。您根本不需要在这种情况下使用 cat,如以下示例所示:


清单 21. 好习惯和坏习惯 10 的示例:使用带和不带 cat 的 grep

~ $ time cat tmp/a/longfile.txt | grep and

2811

 

real    0m0.015s

user    0m0.003s

sys     0m0.013s

~ $ time grep and tmp/a/longfile.txt

2811

real    0m0.010s

user    0m0.006s

sys     0m0.004s

~ $

 

       此错误存在于许多工具中。由于大多数工具都接受使用连字符 (-) 的标准输入作为一个参数,因此即使使用 cat 来分散 stdin 中的多个文件,参数也通常是无效的。仅当您使用带多个筛选选项之一的 cat 时,才真正有必要在管道前首先执行连接。

 

11. 使用文件名完成

       如果不需要在命令提示符处键入长的、令人费解的文件名,这是不是很棒呢?的确,您不需要这样做。相反,您可以配置最流行的 UNIX Shell 以使用文件名完成。该功能在各个 Shell 中的工作方式略有不同,因此我将向您展示如何在最流行的 Shell 中使用文件名完成。文件名完成使您可以更快地输入并避免错误。懒惰?也许吧。效率更高?当然!

 

常用首字母缩写词

1)        MB:兆字节

2)        HTTP:超文本传输协议

3)        HTTPS:HTTP over Secure Sockets Layer

4)        FTP:文件传输协议

5)        FTPS:FTP over Secure Sockets Layer

6)        LDAP:轻型目录访问协议

 

我正在运行哪种 Shell?

       如果您不知道目前使用的是哪一种 Shell,会怎么样?虽然这个诀窍不是另外 10 个好习惯的正式组成部分,但它仍然很有用。可以使用 echo $0 或 ps -p $$ 命令显示您正在使用的 Shell。对于我来说,运行的是 Bash Shell。


清单 1. 确定您的 Shell

$ echo $0

-bash

$ ps –p $$

PID TTY           TIME CMD

6344 ttys000    0:00.02 –bash

 

C Shell

       C Shell 支持最直接文件名完成功能。设置 filec 变量可启用该功能。(您可以使用命令 set filec。)在您开始键入文件名后,可以按 Esc 键,Shell 将完成文件名,或完成尽可能多的部分。例如,假设您拥有名为 file1、file2 和 file3 的文件。如果您键入 f,然后按 Esc 键,将填充 file,而您必须键入 1、2 或 3 来完成相应的文件名。

 

Bash

       Bash Shell 也提供了文件名完成,但使用 Tab 键代替 Esc 键。您在 Bash Shell 中不需要设置任何选项即可启用文件名完成,该选项是缺省设置的。Bash 还实现了其他功能。键入文件名的一部分后,按 Tab 键,如果有多个文件满足您的请求,并且您需要添加文本以选择其中一个文件,那么您可以多按 Tab 键两次,以显示与您目前键入的内容相匹配的文件的列表。使用之前名为 file1、file2 和 file3 的文件示例,首先键入 f。当您按一次 Tab 键时,Bash 完成 file;再按一次 Tab 键时,将展开列表 file1 file2 file3。

 

Korn Shell

       对于 Korn Shell 用户,文件名完成取决于 EDITOR 变量的值。如果 EDITOR 设置为 vi,那么您键入部分名称,然后按 Esc 键,后跟反斜杠 (\) 字符。如果 EDITOR 设置为 emacs,那么您键入部分名称,然后按两次 Esc 键以完成文件名。

 

12. 使用历史扩展

       如果您为一系列命令使用相同的文件名,会发生什么情况?当然,有一种快捷方式可以快速获得您上次使用的文件名。如清单 2 所示,!$ 命令返回前一个命令使用的文件名。从文件 this-is-a-long-lunch-menu-file.txt 中搜索单词 pickles 的出现位置。搜索结束后,使用 vi 命令来编辑 this-is-a-long-lunch-menu-file.txt 文件,而不需要重新键入文件名。您使用感叹号 (!) 来访问历史,然后使用美元符号 ($) 返回前一命令的最后字段。如果您反复用到长文件名,那么这是一个非常好的工具。


清单 2. 使用 !$ 获得前一个命令使用的文件名

$ grep pickles this-is-a-long-lunch-menu-file.txt

pastrami on rye with pickles and onions

$ vi !$   

 

13. 重用以前的参数

       !$ 命令返回某个命令使用的上一个文件名参数。但如果某个命令使用多个文件名,而您只希望重用其中一个文件名,该如何做?!:1 操作符返回某个命令使用的第一个文件名。清单 3 中的示例显示可以如何将此操作符与 !$ 运算符组合使用。在第一个命令中,将一个文件重新命名为更有意义的名称,但为了保持原始文件名可用,创建了一个符号链接。重新命名文件 kxp12.c 以提高可读性,然后使用 link 命令来创建到原始文件名的符号链接,以防在其他位置使用该文件名。!$ 操作符返回 file_system_access.c 文件名,而 !:1 操作符返回 kxp12.c 文件名,该文件名是上个命令的第一个文件名。


清单 3. 组合使用 !$ 和 !:1

$ mv kxp12.c file_system_access.c

$ ln –s !$ !:1

 

14. 使用 pushd 和 popd 管理目录导航

       UNIX 支持各种目录导航工具。最喜欢的两款提高工作效率的工具是 pushd 和 popd。您当然了解 cd 命令用于更改您的当前目录。如果您要在多个目录中导航,但希望能够快速返回某个位置,该如何做?pushd 和 popd 命令创建一个虚拟目录堆栈,pushd 命令用来更改您的当前目录并将其存储在堆栈中,而 popd 命令用来从堆栈的顶部移除目录并使您返回该位置。您可以使用 dirs 命令来显示当前目录堆栈,而不会压入或弹出新目录。清单 4 显示如何使用 pushd 和 popd 命令在目录树中快速导航。


清单 4. 使用 pushd 和 popd 在目录树中导航

$ pushd .

~ ~

$ pushd /etc

/etc ~ ~

$ pushd /var

/var /etc ~ ~

$ pushd /usr/local/bin

/usr/local/bin /var /etc ~ ~

$ dirs

/usr/local/bin /var /etc ~ ~

$ popd

/var /etc ~ ~

$ popd

/etc ~ ~

$ popd

~ ~

$ popd

 

       pushd 和 popd 命令还支持使用参数处理目录堆栈。使用 +n 或 -n 参数,其中 n 是一个数字,您可以向左或向右移动堆栈,如清单 5 所示。


清单 5. 旋转目录堆栈

$ dirs

/usr/local/bin /var /etc ~ ~

$ pushd +1

/var /etc ~ ~ /usr/local/bin

$ pushd -1

~ /usr/local/bin /var /etc ~

 

15. 查找大型文件

       是否需要找出您的所有空闲磁盘空间被什么占用了?您可以使用以下几个工具来管理您的存储设备。如清单 6 所示,df 命令为您显示每个可用卷上已使用的块的总数,以及空闲空间的百分比。


清单 6. 确定卷的使用情况

$ df

Filesystem        512-blocks      Used  Available Capacity  Mounted on

/dev/disk0s2      311909984 267275264   44122720    86%    /

devfs             224       224          0   100%    /dev

fdesc             2         2          0   100%    /dev

map -hosts        0         0          0   100%    /net

map auto_home    0         0          0   100%    /home

 

       是否希望查找大型文件?使用 find 命令时附带 -size 参数。清单 7 显示了如何使用 find 命令来查找大于 10MB 的文件。请注意,-size 参数以 KB 为单位计量大小。


清单 7. 查找大于 10MB 的所有文件

$ find / -size +10000k –xdev –exec ls –lh {}\;

 

16. 不使用编辑器创建临时文件

       以下是一个简单示例:您需要快速创建一个简单临时文件,但不希望启动您的编辑器。使用带有 > 文件重定向操作符的 cat 命令。如清单 8 所示,使用不带文件名的 cat 命令只回显向标准输入键入的任何内容;> 重定向将该输入捕获到指定的文件中。请注意,您在结束键入时必须提供文件结束字符,通常为 Ctrl-D。


清单 8. 快速创建临时文件

$ cat > my_temp_file.txt

This is my temp file text

^D

$ cat my_temp_file.txt

This is my temp file text

 

       需要执行相同操作,但是附加到现有文件而不是创建新文件。如清单 9 所示,改用 >> 操作符。>> 文件重定向操作符向现有文件附加内容。


清单 9.快速向文件附加内容

$ cat >> my_temp_file.txt

More text

^D

$ cat my_temp_file.txt

This is my temp file text

More text

 

17. 使用 curl 命令行实用工具

       curl 命令使您可以使用 HTTP、HTTPS、FTP、FTPS、Gopher、DICT、TELNET、LDAP 或 FILE 协议从服务器检索数据。如清单 10 所示,我可以使用 curl 命令从美国国家气象局了解我所在位置(纽约州布法罗市)的当前天气状况。当与 grep 命令组合使用时,我可以检索布法罗市的天气状况。使用 -s 命令行选项来禁止 curl 处理输出。


清单 10. 使用 curl 检索当前天气状况

$ curl –s http://www.srh.noaa.gov/data/ALY/RWRALY | grep BUFFALO

BUFFALO        MOSUNNY   43  22  43 NE13      30.10R

 

清单 11 所示,您也可以使用 curl 命令来下载 HTTP 托管的文件。使用 -o 参数来指定保存输出的位置。


清单 11. 使用 curl 下载 HTTP 承载的文件

$ curl -o archive.tar http://www.somesite.com/archive.tar

 

       这实际上只是您使用 curl 命令可以完成的操作的提示。您只需在命令提示符处键入 man curl 显示 curl 命令的完整使用信息,就可以开始了解更多内容。

18. 最有效地利用正则表达式

       大量 UNIX 命令使用正则表达式作为参数。从技术角度而言,正则表达式 是表示某种模式的字符串(也就是说,由字母、数字和符号组成的字符序列),用于定义零或更长的字符串。正则表达式使用元字符(例如,星号 [*] 和问号 [?])来匹配其他字符串的部分或全部内容。正则表达式不一定包含通配符,但通配符可以使正则表达式在搜索模式和处理文件时发挥更大的作用。表 1 显示了一些基本正则表达式序列。


表 1. 正则表达式序列

序列

说明

脱字符 (^)

匹配出现在行首的表达式,例如 ^A

美元符号 ($)

匹配出现在行末的表达式,例如 A$

反斜杠 (\)

取消下一个字符的特殊含义,例如 \^

方括号 ([])

匹配括起来的任一字符,例如 [aeiou](使用连字符 [-] 表示范围,例如 [0-9])。

[^ ]

匹配除括起来字符以外的任一字符,例如 [^0-9]

句点 (.)

匹配除行尾之外的任意单个字符

星号 (*)

匹配零个或多个前驱字符或表达式

\{x,y\}

匹配出现过 x 到 y 个和前面相同的内容

\{x\}

精确匹配出现过 x 个和前面相同的内容

\{x,\}

匹配出现过 x 个或更多和前面相同的内容

 

清单 12 显示了与 grep 命令一起使用的一些基本正则表达式。


清单 12. 使用正则表达式和 grep

$ # Lists your mail

$ grep '^From: ' /usr/mail/$USER  

$ # Any line with at least one letter 

$ grep '[a-zA-Z]'  search-file.txt

$ # Anything not a letter or number

$ grep '[^a-zA-Z0-9] search-file.txt

$ # Find phone numbers in the form 999-9999

$ grep '[0-9]\{3\}-[0-9]\{4\}' search-file.txt

$ # Find lines with exactly one character

$ grep '^.$' search-file.txt

$ #  Find any line that starts with a period "."         

$ grep '^\.' search-file.txt

$ # Find lines that  start with a "." and 2 lowercase letters

$ grep '^\.[a-z][a-z]' search-file.txt

 

       有关命令行正则表达式的深入描述,阅读 developerWorks 文章“对话 UNIX,第 9 部分:正则表达式。”

19. 确定当前用户

       有时,您可能希望确定某个特定用户是否运行过您的管理脚本。为找出答案,您可以使用 whoami 命令来返回当前用户的名称。清单 13 显示了独自运行的 whoami 命令;清单 14 显示了使用 whoami 确保当前用户不是根用户的 Bash 脚本的摘录。


清单 13. 从命令行使用 whoami

$ whoami

John


清单 14. 在脚本中使用 whoami

if [ $(whoami) = "root" ]

then

   echo "You cannot run this script as root."

   exit 1

fi

 

20. 使用 awk 处理数据

       awk 命令似乎始终处在 Perl 的阴影下,但它对于简单、基于命令行的数据处理来说是一个快速、实用的工具。清单 15 显示了如何开始使用 awk 命令。若要获取文件中每行文本的长度,请使用 length() 函数。若要查看字符串 ing 是否出现在文件文本中,请使用 index() 函数,该函数返回 ing 首次出现的位置,这样您就可以使用它来进行进一步的字符串处理。若要 tokenize(也就是说,将一行拆分为单词长度的片段)某个字符串,请使用 split() 函数。


清单 15. 基本 awk 处理

$ cat text

testing the awk command

$ awk '{ i = length($0); print i }' text

23

$ awk '{ i = index($0,”ing”); print i}' text

5

$ awk 'BEGIN { i = 1 } { n = split($0,a," "); while (i <= n) {print a[i]; i++;} }' text

testing

the

awk

command

 

       打印文本文件中的指定字段是一项简单的 awk 任务。在清单 16 中,sales 文件包含每个销售人员的姓名,后跟每月销售数字。您可以使用 awk 命令来快速获得每个月的销售总额。缺省情况下,awk 将每个以逗号分隔的值视为不同的字段。您使用 $n 操作符来访问每个字段。


清单 16. 使用 awk 对数据进行汇总

$cat sales

Gene,12,23,7

Dawn,10,25,15

Renee,15,13,18

David,8,21,17

$ awk -F, '{print $1,$2+$3+$4}' sales

Gene 42

Dawn 50

Renee 46

David 46

 

       成为命令行高手需要进行一些实践。按照相同的方式处理问题很简单,因为您已经习惯了。扩展您的命令行资源可以显著提高您的工作效率,并促使您朝着 UNIX 命令行高手的方向前进!

 

 

 

From:

http://www.ibm.com/developerworks/cn/aix/library/au-badunixhabits.html

https://www.ibm.com/developerworks/cn/aix/library/au-unixtips/

-->>转自csdn

人生的礼物

在此记录下,个人很喜欢的一首歌:)

 

人生の贈り物~他に望むものはない~


作詞:楊姫銀  訳詞・作曲:さだまさし


季節の花が これほど美しいことに

歳を取るまで 少しも気づかなかった

美しく老いてゆくことが どれほどに

難しいかということさえ 気づかなかった


もしももう一度だけ若さを くれると言われても

おそらく私は そっと断るだろう


若き日のときめきや 迷いをもう一度

繰り返すなんて それはもう望むものではない


それが 人生の秘密

それが 人生の贈り物


季節の花や人の 生命の短さに

歳を取るまで 少しも気づかなかった

 

人は憎み諍(いさか)い そして傷つけて

いつか許し 愛し合う日が来るだろう


そして言葉も要らない友に なってゆくのだろう

迷った分だけ 深く慈しみ


並んで座って 沈む夕日を一緒に眺めてくれる

友がいれば 他に望むものはない


それが 人生の秘密

それが 人生の贈り物


季節の花が これほど美しいことに

歳を取るまで 少しも気づかなかった


私の人生の花が 散ってしまう頃

やっと花は 私の心に咲いた


並んで座って 沈む夕日を一緒に眺めてくれる

友がいれば 他になにも望むものはない

  
他になにも 望むものはない

他になにも 望むものはない


それが 人生の秘密

それが 人生の贈り物

 

 

译++++++++++++++++++++++++++

 

季节的花竟然如此的美,

年华老去之前竟然连一点也没有觉察到;
优雅的慢慢老去是如此的不容易,就更没有意识到了;
 
如果有人对我说再给我一次年轻的机会,
或许我是会谢绝的,
年轻时的心动与迷惑并非是我期待的;
 
那就是人生的秘密,那就是人生的礼物;
 
季节的花和人的生命都 是如此的短促,
年华老去之前竟然连一点也没有觉察到;
人们互相憎恨、争论然后受伤,
什么时候才能互谅互爱,
然后变成连言语也不需要的朋友呢;
 
在我深陷迷惑时给我真诚的怜爱,
和我并肩坐在一起眺望慢慢落下的夕阳,
有这样的朋友那我就别无所求了;
 
那就是人生的秘密,那就是人生的礼物;
 
季节的花和人的生命都是如此的短促,
年华老去之前竟然连一点也没有觉察到;
我的生命之花就要凋零的时候,
花终于在我的心中绽放了;
 
和我肩并肩坐在一起眺望慢慢落下的夕阳,
有这样的朋友那我就别无所求了;
 
别无所求了,
别无所求了,
 
那就是人生的秘密,那就是人生的礼物;




Host by is-Programmer.com | Power by Chito 1.3.3 beta | © 2007 LinuxGem | Design by Matthew "Agent Spork" McGee