前段时间公司封闭开发,就在封闭的前一天感冒发烧,为了封闭,一顿猛药下去,烧是退了,却在扁桃附近爆发出来——扁桃发炎加溃疡,搞了十多天才好啊,天天喝稀饭啊……所以请大家原谅这么久没有续上学习笔记。顺便:过两天继续封闭,所以这个笔记更新速度可能不会很快了,我尽力。

函数

  函数是Powershell里一个非常重要的东西,与CMD比较起来,这绝对是一个亮点。CMD中只能用“标签”+CALL来模拟函数,而Powershell不仅支持函数,还支持3种类型的函数:普通函数(Function)、过滤器(Filter)和管道函数(Pipeline Function)。除此之外,Powershell的参数解析也是非常智能和强大——当然,参数形式的约定是必不可少的部分。

  函数可以为一系列的操作提供一个快捷命令,而且还可以通过参数来改变函数内的流程或运算结果。还是先来一个示例:

  1. PS C:\Users\james> f:
  2. PS F:\> function cd~ { cd c:\users\james } 
  3. PS F:\> cd~
  4. PS C:\users\james>

  这里定义了一个名为“cd~”的函数,目的是直接回到用户目录,就像Linux的“cd ~”一样。这里function是定义函数的关键字,cd~是函数名,{}中的部分则是函数体。——这里还没用到参数,这个,后面再说。执行“cd~”,实际是执行了函数体里面的内容。

  当然,如果一个函数比较复杂,要一行写完是比较痛苦的。那么也可以分多行来写,比如

  1. PS C:\users\james> function cd~ { 
  2. >> cd c:\users\james 
  3. >> }
  4. >>
  5. PS C:\users\james>

  当然,这样写不太方便,因为你在写到最后一行时如果发现前面有错,连修改的机会都没有。不过,如果把一段程序或者函数定义写在脚本文件中,再来执行脚本就会方便得多了——我想,关于脚本文件,在前面已经说过,这里就不用多说了。

函数的参数

  为了演示参数,我们用另一个例子。这个例子会将参数转为大写输出:

  1. PS F:\> function toUpper { $args[0].toUpper() }
  2. PS F:\> toUpper "james"
  3. JAMES
  4. PS F:\>

  这个示例中,用到了未命名参数数组$args。只要是没有命名的参数都会按顺便存在在这个数组中。如果是多个未命名参数,我们可以用用一个循环来依次处理。比如:

  1. PS F:\> function toUpper { 
  2. >> foreach ($a in $args) { $a.toUpper() } 
  3. >> 
  4. >>
  5. PS F:\> toupper hello james fancy
  6. HELLO
  7. JAMES
  8. FANCY
  9. PS F:\>

  循环是控制流程的内容,之前的笔记还没提到。这篇笔记主要是记函数,所以也暂时略过不说。

命名参数

  不过这里有一个问题却不得不说——未命名参数。顾名思义,未命名参数就是没有名字的参数;而且,既然有未命名参数,就一定有命名参数。那么命名参数又是什么呢?还是看例子(这次的例子是写的脚本文件):

  1. # sample.ps1
  2. # 命名参数示例
  3. function hello($name, $isMale) {
  4. if ([bool]::parse($isMale)) {
  5. "Hello Mr. $name"
  6. } else {
  7. "Hello Ms. $name"
  8. }
  9. }
  10. hello James true # 参数值为按顺便赋予命名参数
  11. hello -ismale false Jenny # 指定了名称的参数值会赋给对应的命名参数,其它的按顺序赋给其它命名参数

  运行结果如下:

  1. PS F:\james\Desktop> .\sample.ps1
  2. Hello Mr. James
  3. Hello Ms. Jenny

多余的参数

  上面的示例中有两个调用函数的示例。第一个没有为参数值指定名称,那么函数调用时会按顺序把参数值赋给参数列表中的命名参数;而第二种调用,为ismale参数指定了值,那么会先将指定了名称的参数值赋给相应的命名参数,其它的参数值再按顺序赋予其它命名参数。现在有一个问题:如果赋予所有命名参数之后还有参数传入,这些参数是否可以通过$args来访问呢?继续做实验,把上面的示例稍做改动:

  1. # sample.ps1
  2. # 多余的参数示例
  3. function hello($name, $isMale) {
  4. if ([bool]::parse($isMale)) {
  5. "Hello Mr. $name"
  6. } else {
  7. "Hello Ms. $name"
  8. }
  9. foreach ($a in $args) { 
  10.  "MORE ARG: $a" 
  11. }
  12. }
  13. hello James true a b c d e f g

  运行结果

  1. PS F:\james\Desktop> .\sample.ps1
  2. Hello Mr. James
  3. MORE ARG: a 
  4. MORE ARG: b 
  5. MORE ARG: c 
  6. MORE ARG: d 
  7. MORE ARG: e 
  8. MORE ARG: f 
  9. MORE ARG: g

默认参数值

  其实多做做实验,答案都是显而易见的。继续下一个问题:“[bool]::parse($isMale)”能不能简化?[bool]::parse其实是调用了System.Boolean的静态方法Parse来将字符串解析为布尔类型的值。如果我们直接传入布尔类型的参数不就可以简化了么?就像这样

  1. # sample.ps1
  2. function hello($name, $isMale) {
  3. if ($isMale) {
  4. "Hello Mr. $name"
  5. } else {
  6. "Hello Ms. $name"
  7. }
  8. }
  9. hello James $true
  10. hello -ismale $false Jenny

  其实,还可以更简单,比如对于男士,省略第2个参数……当然,现在这个脚本不行,试试就知道了,可以省略$isMale参数的是女士。再做点改动:

  1. # sample.ps1
  2. # 默认参数值示例
  3. function hello($name, $isMale=$true) {
  4. if ($isMale) {
  5. "Hello Mr. $name"
  6. } else {
  7. "Hello Ms. $name"
  8. }
  9. }
  10. hello James
  11. # Hello Mr. James

开关[switch]参数

  既然isMale是一个布尔,在控制台脚本里,会很容易让人想起“开关”,即通过一个参数是否存在来表示两种不同的参数值。比如,如果加了“-ismale”参数,则表示男士,否则表示女士——哦,应该换一下,因为不加参数为默认形式,而我们前面约定的默认情况是男士,所以开关参数应该改为“-isFemale”,不过既然是开关,那“is”也可以省了,就是“-female”。示例:

  1. # sample.ps1
  2. # [switch]参数值示例
  3. function hello($name, [switch] $female) {
  4. if (!$female) {
  5. "Hello Mr. $name"
  6. } else {
  7. "Hello Ms. $name"
  8. }
  9. }
  10. hello James
  11. hello Jessy -female
  12. # Hello Mr. James

  有注意到定义参数时指定的[switch]标记么?这叫参数类型。当然[switch]只是参数类型中的一种……

指定参数的类型

  除此之外,还可以为参数指定类型,这样的话,只要给予的参数值不是指定的类型,或者不能转换为指定的类型,就会抛出错误。当然,指定了类型的参数,在函数内进行处理时,往往可以活力掉类型转换的步骤,比如我们想把年、月、日3个参数拼成一个8位长度的日期字符串,下面哪个函数是可以完成呢?

  1. # sample.ps1
  2. # 指定类型的参数示例
  3. function add1($a, $b, $c) {
  4. $a + $b + $c
  5. }
  6. function add2([string]$a, $b, $c) {
  7. $a + $b + $c
  8. }
  9. add1 2010 10 21 # 输出:2042
  10. add2 2010 10 21 # 输出:20111021

  由于没有指定类型,add1的三个参数都被当作int型进行处理,相加的结果是2042。而add2中,将$a申明为string类型,虽然$b和$c仍然是被当作int型进行处理,但是“+”遇到不同类型的运算时是自动转为其左边的类型进行运算,所以是字符串相连,结果20111021。

函数的返回值

  Powershell关于函数返回值这个问题,比较复杂。在其它脚本或者语言中,通常来说,通过return之类的关键返回的才是返回值,而Powershell不同,只有是输出到Output的内容,都是返回值,比如

  1. # sample.ps1
  2. function test() {
  3. write-output "Hello"
  4. "James Fancy"
  5. return "OK"
  6. }
  7. $a = test
  8. $a.GetType().FullName
  9. $a

  它的输出:

  1. PS F:\james\Desktop> .\sample.ps1
  2. System.Object[]
  3. Hello
  4. James Fancy
  5. OK

  可以看出来,test函数返回了包含3个值的一个数组,除了最后的return外,前面两个都是写入管道的。哦,管道……这又是一个复杂的东西,后面再来复习。现在只需要记得write-output输出,直接字面值或者变量值输出以及return都会产生返回值就对了。

  很明显,Powershell的函数允许一次返回多个值,这些值都保存在一个数组中。当然,如果函数只返回一个值,那就不需要数组了,比如把上面的示例精简一下:

  1. # sample.ps1
  2. function test() {
  3. "James Fancy"
  4. }
  5. $a = test
  6. $a.GetType().FullName # 输出:System.String
  7. $a # 输出:James Fancy

Filter,过滤器函数

  除了定义函数之外,也可以定义过滤器。过滤器可以对通过管道进来的内容进行过滤,比如下面这个列子就是为了只列出.exe文件:

  1. # sample.ps1
  2. filter test() {
  3. # 只列出.exe扩展名的文件
  4. if ($_.extension -eq ".exe") { $_ }
  5. }
  6. dir | test

  运行结果:

  1. PS E:\james\Desktop> cd c:/windows
  2. PS C:\windows> E:\james\Desktop\sample.ps1
  3. 目录: C:\windows
  4. Mode LastWriteTime Length Name
  5. ---- ------------- ------ ----
  6. -a--- 2009-7-14 9:14 65024 bfsvc.exe
  7. -a--- 2011-6-9 11:10 642240 bjzq.exe
  8. -a--- 2010-1-31 15:23 2614272 explorer.exe
  9. -a--- 2009-7-14 9:14 13824 fveupdate.exe
  10. -a--- 2009-7-14 9:14 497152 HelpPane.exe
  11. -a--- 2009-7-14 9:14 15360 hh.exe
  12. -a--- 2011-3-21 23:21 78848 KMSEmulator.exe
  13. -a--- 2011-3-21 23:26 151552 KMService.exe
  14. -a--- 2009-11-28 7:52 179712 notepad.exe
  15. -a--- 2009-7-14 9:14 398336 regedit.exe
  16. -a--- 2009-6-11 5:41 49680 twunk_16.exe
  17. -a--- 2009-7-14 9:14 31232 twunk_32.exe
  18. -a--- 2009-6-11 5:42 256192 winhelp.exe
  19. -a--- 2009-7-14 9:14 9728 winhlp32.exe
  20. -a--- 2009-7-14 9:14 9216 write.exe
  21. -a--- 2011-8-10 12:27 34512 xinstaller.exe
  22. PS C:\windows>

  注意脚本中最后一句“dir | test”,意思就是把dir的输出通过管道传递给test进行处理。再看test函数的内容,管道中传入的每一项都由特殊变量$_引用。test对传入的每一项都进行判断,将扩展名为.exe的文件对象输出,其余的丢弃。

管道函数

  其实,过滤器是一种特殊的函数,管道函数的简化版。管道函数也是一种特殊的函数,它包含3个部分,begin、process和end。管道输出在进入管道函数的时候,会首先运行begin区域的脚本,仅运行一次;之后从管道进来的每个对象都会经历process过程;所有项结束之后,会触发end区域的脚本。而过滤器就是只定义了process区的管理函数。还是来看例子:

  1. # sample.ps1
  2. function test() {
  3. begin {
  4. "处理开始了"
  5. }
  6. process {
  7. if ($_ -like "a*") { $_ }
  8. }
  9. end {
  10. "处理完成了"
  11. }
  12. }
  13. # 这次示例用一个数组来演示
  14. $("a", "ab", "bac", "b", "bc", "ac") | test

  输出:

  1. PS E:\james\desktop> E:\james\Desktop\sample.ps1
  2. 处理开始了
  3. a
  4. ab
  5. ac
  6. 处理完成了

  管道函数的3个块都可以省略,包括process块,只不过如果省略了process块之后,这个函数就没啥意义了。不过根据实际情况,begin和end块倒是经常被省略的。

函数库

  前面关于运算符的笔记中提到了点号(.)运算符可以用于引入一个脚本,而这个脚本就类似于C/C++中#include的方式被引入到当前位置并执行。那么,如果这个脚本里面只包含函数定义,而不包含其它内容,那么这个脚本就是一个函数库。每次使用该函数库的时候,只需要使用点号运算符引入即可。比如上面的例改稍作改动:

  1. # sample.ps1
  2. function test() {
  3. process {
  4. if ($_ -like "a*") { $_ }
  5. }
  6. }

  然后在Powershell控制台运行:

  1. PS E:\james\desktop> . .\sample.ps1 
  2. PS E:\james\desktop> $("a", "ab", "bac", "b", "bc", "ac") | test
  3. a
  4. ab
  5. ac
  6. PS E:\james\desktop>

  如果有兴趣试试不使用点号,而是直接运行脚本,那么第二条命令就会出错是,因为test未定义。

本文转自边城__ 51CTO博客,原文链接:http://blog.51cto.com/jamesfancy/694700,如需转载请自行联系原作者

Powershell学习笔记——函数和函数库相关推荐

  1. jquery学习笔记及常用函数封装

    二.JQuery 学习笔记及常用函数封装 https://download.csdn.net/download/weixin_42530002/13087988 1.JQuery入门 (1).css选 ...

  2. c++学习笔记内联函数,函数重载,默认参数

    c++学习笔记内联函数,函数重载,默认参数 1 inline内联函数 C++中的const常量可以替代宏常数定义,如: const int A = 3;  #define A 3 C++中是否有解决 ...

  3. c语言中void arrout,c语言学习笔记(数组、函数

    <c语言学习笔记(数组.函数>由会员分享,可在线阅读,更多相关<c语言学习笔记(数组.函数(53页珍藏版)>请在人人文库网上搜索. 1.数组2010-3-29 22:40一维数 ...

  4. IOS学习笔记07---C语言函数-scanf函数

    2013/8/7 IOS学习笔记07---C语言函数-scanf函数 ------------------------------ qq交流群:创梦技术交流群:251572072            ...

  5. IOS学习笔记07---C语言函数-printf函数

    IOS学习笔记07---C语言函数-printf函数 0 7.C语言5-printf函数 ------------------------- ----------------------------- ...

  6. IOS学习笔记06---C语言函数

    IOS学习笔记06---C语言函数 --------------------------------------------  qq交流群:创梦技术交流群:251572072              ...

  7. STATA学习笔记:egen函数

    STATA学习笔记:egen函数 1. egen (1)mean() webuse egenxmpl,clear egen avg = mean(cholesterol) gen deviation ...

  8. Python学习笔记11:函数修饰符

    Python学习笔记11:函数修饰符 Python有很多有趣的特性,其中函数修饰符就是一个. 我们在之前的那个web应用示例中用过如下写法: @web.route('/log') @符号后边的,就是一 ...

  9. Hive学习笔记三之函数操作

    文章目录 5 函数 5.1 系统内置函数 5.2 常用内置函数 5.2.1 空字段赋值 5.2.2 CASE WHEN THEN ELSE END(类似于java中的switch case) 5.2. ...

  10. PowerShell 学习笔记 - 1 PS Core 基础

    PowerShell 学习笔记 - 1 PS Core 基础 本章主要探讨 PowerShell 核心,主要基于 Linux 平台上的 PowerShell Core 实现,实际上于 Windows ...

最新文章

  1. python、PyTorch图像读取与numpy转换
  2. PHP5.5安装GeoIP扩展
  3. L、TEXT()、_TEXT()和_T()的区别
  4. 线程池默认多少个线程_我需要多少个线程?
  5. 高中数学40分怎么办_2019年第35届全国高中数学联赛试题及参考答案
  6. 多态计算器的开发 c# 1614095334
  7. CIT 中文笔记完整版
  8. 【训练计划】ACM题集以及各种总结大全
  9. 计算机游戏有哪几种,这些游戏你玩过几个? 你认为最经典的电脑游戏有哪些?
  10. 真人拳皇项目第七次Scrum总结——史经浩
  11. Eclipse插件Mylyn管理上下文任务管理
  12. 百度大脑开放日·互联网内容安全线上专场报名中!
  13. F22.YOLO深入理解(V1-V3)个人感觉非常详细
  14. 电商如何利用API接口获取商品信息数据
  15. TeamSpeak 服务器LINUX下配置
  16. 2021年茶艺师(初级)考试技巧及茶艺师(初级)试题及解析
  17. Android如何避免抓包
  18. You are currently rebasing branch ‘csindex/feature/index_info‘ on ‘d2ef4210a3‘.
  19. 【架构】分布式系统及相关技术栈初了解
  20. Linux vi 文本代码时显示行号或不显示行号

热门文章

  1. 断崖式下跌 - 创业者的噩梦
  2. 期货仓储费是什么(期货交易仓储费)
  3. Mac office365 自动扣费问题解决记录
  4. 日语美文欣赏(中日对照)
  5. 【小波分析】七、小波分析与非线性逼近(下)
  6. 小丑机器人乐高_5岁试听课程——《小丑机器人》教案
  7. 2021腾讯实习一面复盘-小丑竟是我自己
  8. Vue项目实战 —— 哔哩哔哩移动端开发
  9. gclone和fclone转存教程
  10. yjk的波库在哪里_[稀有资源]盈建科YJK地震波文件