powershell 学习笔记

最近在学习PowerShell的一些基础知识,这边记录下一些学习笔记,都很简单,也没有涉及管道,cmdlets的用法。

最开始犯的第一个错误

在编写PowerShell脚本的时候,有一点刚开始很容易出现错误,就是扩展名是.ps1(数字)不是.psl(字母)。

变量

变量创建

PowerShell不必显示声明变量,只需要在用到的时候创建即可。变量必须以 $ 作前缀,随后可以是数字、字母、下划线的任意字符(也可以使用汉字等)。PowerShell的变量是不区分大小写的:

一些特殊的字符如$等,如果变量名要使用这些字符,需要用花括号将$后面的后缀括起来:

由于PowerShell支持对象,所以使用等号(=)可以把任何数据包括cmdlet命令赋值给一个变量,比如我们把 ls 的执行结果赋给一个变量, ls返回的结果并不是一个纯文本,相反是一个object数组,每项的类型是DirectoryInfo:

predefined变量

在PowerShell中还有一些是PowerShell启动就会加载的变量,称为自动变量:

变量 说明
$$ 会话所收到的最后一行中的最后一个令牌
$? 最后一个操作的执行状态。如果最后一个操作成功,则包含 TRUE,失败则包含 FALSE
$^ 会话所收到的最后一行中的第一个令牌
$_ 管道对象中的当前对象。在对管道中的每个对象或所选对象执行操作的命令中,可以使用此变量
$Args 包含由未声明参数和/或传递给函数、脚本或脚本块的参数值组成的数组。在创建函数时可以声明参数,方法是使用 param 关键字或在函数名称后添加以圆括号括起、逗号分隔的参数列表
$ConsoleFileName 包含在会话中最近使用的控制台文件 (.psc1) 的路径。在通过 PSConsoleFile 参数启动Windows PowerShell 或使用 Export-Console cmdlet 将管理单元名称导出到控制台文件时,将填充此变量
$PsCmdlet 包含操作系统中当前所用的区域性的名称。区域性确定数字、货币和日期等项的显示格式。这是系统的 System.Globalization.CultureInfo.CurrentCulture.Name 属性的值。要获取系统的 System.Globalization.CultureInfo 对象,请使用 Get-Culture cmdlet

特殊的变量:子表达式

由 $+圆括号+表达式 构成的变量属于子表达式变量,这样的变量会先计算表达式,然后把表达式的值返回。例如 变量$(3+6),可以简写成(3+6),甚至可以简写成3+6。子表达式变量也可以嵌套在文本中,例如”result=$(3+6)”。在处理对象的属性时,会大量的用到表达式变量。

变量的类型:

PowerShell还支持强类型,在创建变量的时候,可以在前面用中括号加入数据类型,当试图赋值一个类型定义域内的值就会出现错误,避免了弱类型所带来的一些弊端:

Powershell 默认支持的.NET类型如下。

[array],[bool],[byte],[char],[datetime],[decimal],[double],[guid],[hashtable],[int16],[int32],[int],[int64],[long],[nullable],[psobject],[regex],[sbyte].[scriptblock],[single],[float],[string],[switch],[timespan],[type],[uint16],[uint32],[uint64],[ XML ]

变量的作用域:

变量 说明
$global 全局变量,在所有的作用域中有效,如果你在脚本或者函数中设置了全局变量,即使脚本和函数都运行结束,这个变量也任然有效。
$script 脚本变量,只会在脚本内部有效,包括脚本中的函数 ,一旦脚本运行结束,这个变量就会被回收。
$private 私有变量,只会在当前作用域有效,不能贯穿到其他作用域。
$local 默认变量,可以省略修饰符,在当前作用域有效,其它作用域只对它有只读权限。

数组

创建数组:

  • 使用逗号创建:
  • 连续数组可以直接使用类似 1..3来创建,如$arr = 1..3表示创建一个存储1,2,3的变量:
  • 可以设置数组元素的类型,使用[]括起来,如:[int[]]表示创建一个存储int元素的数组,如果没有指定数组元素的类型,则可以保存不同类型的元素:
  • 空数组创建: $arr = @()
  • 只有一个元素的数组创建: $arr = , ‘test’ ,+ 以逗号开始+ 。
  • @(ele1, ele2, ele3) 形式创建数组

数组复制:

数组属于引用类型,如果要赋值一个数组,需要使用 Clone() 方法。

Map

创建Map的方式为: $map = @{key=value, key1=value1.....}
使用与其他语言类似,可以直接使用.(点)来添加新的键-值对和访问键-值:

PowerShell函数:

函数的定义以function开头,然后是函数名,参数,函数体,与其他语言类似。
特别的地方是在PowerShell函数的参数中,前面提到的$args可以识别任意个数的参数,它是一个数组:

function foo
{
if($args.Count-eq0)
{
"hello world"
}
else
{
$args|foreach{"hello world,$($_)"}
}
}

调用:

  1. sayHello
  2. sayHello param1
  3. sayHello param1, param2

另外参数可以是弱类型的,不指定参数支持的类型,可以采用强类型的参数,具体方式与变量创建类似。

Function foo([int] param1, [xml] param2){
.......
}

PowerShell 脚本安全性:

PowerShell采用数字签名证书来对脚本的来源进行验证,当运行一个脚本时,PowerShell会进行自动验证。关于创建证书与给PowerShell脚本进行签名可以参考:
http://www.pstips.net/powershell-scripts-signature.html

用户需要设置PowerShell的ExecutionPolicy,当设置为AllSigned和RemoteSigned时,自动验证就会激活。ExecutionPolicy的设置说明:
http://technet.microsoft.com/en-us/library/ee176961.aspx

— Restricted

默认值,不加载配置文件或运行脚本

— AllSigned

要求所有脚本和配置文件由可信发布者签名,包括在本地计算机编写的脚本。

RemoteSigned

要求从 Internet 下载的所有脚本和配置文件均由可信发布者签名

Unrestricted

加载所有配置文件并运行所有脚本。如果运行从 Internet 下载的未签名脚本,则系统将提示您需要相关权限才能运行该脚本

Bypass

阻止任何执行项,不显示警告和提示

Undefined

从当前作用域删除当前分配的执行策略。此参数将不会删除在组策略作用域中设置的执行策略


执行: Set-ExecutionPolicy RemoteSigned

PowerShell中使用.Net对象:

在PowerShell 中,可以使用 New-Object 命令实例化一个.Net FrameWork中的类的实例,使用 -TypeName 指定类型名曾,-ArgumentList 传递参数,然后就可以使用实例的方法了:

参考:

  1. http://technet.microsoft.com/en-us/library/dd347574.aspx
  2. http://www.pstips.net/powershell-online-tutorials

python virtualenv 使用

virtualenv是python开发中常用的一个工具,用来创建一个虚拟的环境,将项目需要用到的package安装进这个虚拟环境中,与系统全局的package进行隔离,避免影响全局的package结构。要使用这些安装在虚拟环境中的package,只要activate就行了。

安装

安装virtualenv工具(Ubuntu)

sudo apt-get install python-virtualenv

使用

创建项目的目录,作为虚拟环境

$ mkdir project_name
$ cd project_name
$ virtualenv env
New python executable in env/bin/python
Installing setuptools............done.
Installing pip...............done.

激活虚拟环境

$ cd PATH_TO_YOUR_PROJECT_DIR
$ source env/bin/activate

这时候shell提示符前面会多个标志: (env):

这样就可以在这个虚拟环境下安装项目所需的package,

deactivate

不使用虚拟环境时,可以进入目录,然后执行deactivate命令即可

$ cd PATH_TO_YOUR_PROJECT_DIR
$ deactivate

使用epiceditor和pythonmakrdown遇到的no-break问题

最近在学习webpy(好像学了一段时间了= =),用来捣腾个博客系统(好吧,其实只是拿来学习入门python的),使用markdown在线编
辑器epiceditor编写文章,然后post方式提交到后台,后台使用python markdown将markdown解析
成html, 使用的过程中就发现如果markdown文本中存在多个空格,比如你要输入一段代码,markdown的语法就是前面留4个空格,如果我们后台直接解析,就无法正确地解析成<pre>和<code>标签。
被这个问题搞了好久,最后看了下epiceditor代码,找到了其中 exportFile 方法中的一段注释:

// 2 spaces in a content editable actually converts to:
// 0020 00a0, meaning, "space no-break space". So, manually convert
//no-break spaces to spaces again before handing to marked.

意思就是说,两个空格实际上是编码为 spaceno-break space, 他们的unicode编码不一样,所以python markdown在解析的时候就会出现问题,找到了问题的所在,我们就开始fix吧。
既然两个空格被编码为 spaceno-break space, 所以我们就要在 python markdown convert之前,通过replace方法将 no-break space 变成正常的 space, 然后再调用markdown的convert方法将
markdown转化为HTML:

post_markdown_content_rp = post_markdown_content.replace(u'\xa0', u' ')
post_html_content = md.convert(post_markdown_content_rp)

这样python markdown就可以正确的convert了,初次遇见这样的问题,感觉无从下手,很是头疼,折腾了一整天,其实多看看源代码熟悉理解其中的原理,还是比较容易解决的 :)。

这里还有一个需要注意的地方,就是使用epiceditor在线编辑器的时候,如果是要预先载入一个已经存在的markdown文本对其进行修改编辑(比如说我们在做一个博客,实现对文章的编辑功能)
如果两个空格都是 break的话,则显示出来的不会有空格,因此还要对其还原操作,这现在这个项目中,我就直接保存没replace “no-break space”之前的markdown文本,要进行修改就直接载入这个
文本就行了。

被这个问题折腾了很久,解决了记录下,以免以后忘记。

webpy中在子应用内使用session

背景

最近在学习webpy,做了个博客的小项目(webpy-blog)
在这个项目中,我将博客的后台管理当作是整个应用的子应用,这里涉及到用户登录后将用户的一些信息(比如id, hash等)存储
在session的问题,由于webpy默认session只能在主应用中共享,在子应用中即使import都不行。

子应用的使用

子程序的使用是为了更好地控制大型web应用,在webpy-blog中,我将后台管理单独剥离出来作为子程序,controllers.blogAdmin模块为其
controller。然后为子程序设置url映射。

import web
admin_prefix = 'controllers.blogAdmin'
admin_urls = (
'/login', admin_prefix + 'Login',
'/logout', admin_prefix + 'Logout',
.....
)

然后在父程序的url配置中,配置中

import web
from config.admin_url import admin_urls #import 为子程序配置的url
admin_app = web.application(admin_urls, locals())
prefix = 'controllers.pblog'
urls = (
'/', prefix + 'Index'
.....
'/admin', admin_app
)

以上配置,定义了’/admin’跳转至admin_app子程序。这个就可以在webpy中使用子程序了。
在为子程序涉及url模式的时候, 路径是父应用剥离后的路径 ,比如上述配置,则在子程序中的url '/login', 运行时对应的url
'/admin/login'

在子程序中使用session

在本项目中,由于用户登录后,要在session中存储信息,故要在子程序中使用session, 这时候可创建一个被web.loadhook加载的处理器(processor),我们在程序入口处创建,即在创建web.application的时候去创建,被加载。

import web
import config.url
import urls
app = web.application(urls, locals())
session = web.session.Session(app, web.session.DiskStore('userinfo'),initializer={'id':0,"seed":0,"hash":""})
def session_hook():
''' 定义一个hook,用于在子程序中使用session '''
web.ctx.session = session
app.add_processor(web.loadhook(session_hook)
if __name__ == '__main__':
app.run()

这样就可以在子应用中使用session了,例: web.ctx.session.id = 1