powershell

同学说他在windows下需要找到文件中包含给出字符的那些文件,非常浪费时间。其实在shell中一个find+grep就可以搞定这个事情了。但是在windows上,确实有点麻烦,毕竟我也不会powershell,虽然很久很久之前学过一段时间,但是感觉好难,所以今天打算再学习一下,原因:无聊

powershell

下载

由于我是日常使用linux的,所以不想再打开windows用了,其实也可以开虚拟机用。但是我发现可以在linux中安装powershell,因为这个powershell现在已经可以跨平台使用了。但是我的archlinux就算了,所以我把它安装到raspberry上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 官方给出的操作步骤,但是wget从github下载速度太慢了
# Update package lists
sudo apt-get update

# Install libunwind8 and libssl1.0
# Regex is used to ensure that we do not install libssl1.0-dev, as it is a variant that is not required
sudo apt-get install '^libssl1.0.[0-9]$' libunwind8 -y

# Download and extract PowerShell

# Grab the latest tar.gz
wget https://github.com/PowerShell/PowerShell/releases/download/v7.0.0/powershell-7.0.0-linux-arm32.tar.gz

# Make folder to put powershell
mkdir ~/powershell

# Unpack the tar.gz file
tar -xvf ./powershell-7.0.0-linux-arm32.tar.gz -C ~/powershell

# Start PowerShell
~/powershell/pwsh

# Start PowerShell from bash with sudo to create a symbolic link
sudo ~/powershell/pwsh -c New-Item -ItemType SymbolicLink -Path "/usr/bin/pwsh" -Target "$PSHOME/pwsh" -Force

学习网址

微软官网

在线学习

还是开虚拟机算了

哈,下了一个晚上,一看,还没下完,算了,开虚拟机玩

在用powershell时需要以管理员运行,否则很多命令是没有权限的。

概念

  1. 一切皆对象:powershell不同与linux的shell,linux shell是基于文本的,有各种不同的工具都可以对文本进行各种操作达到需要的目的。但是powershell是对象,所有输出都是对象,那么思考方式就不一样了,对象都有方法和属性。
  2. powershell使用了许多c#的语法
  3. powershell脚本以.ps1结尾,可直接在powershell中调用

帮助

其实我最大的心得就是帮助文档是最重要的东西,使用好它,不用记命令都行。

  • 使用man command来获取帮助信息,那么首先需要更新帮助信息,update-help,man其实是help的一个别名

  • 使用command -?获取帮助

  • get-help command -example

命令命名格式

powershell使用verb-noun动-名词的命名格式,所以还是比较好记的。

比如需要查询所有以get开头的命令:get-command -verb get,查询所有包含service的命令:get-command -noun service

命令参数

与linux shell一样,powershell的参数也是用-标识。其实很多都是借鉴的shell,比如说pipe

命令别名及配置文件

在powershell中可以使用很多熟悉的linux命令,比如:ls,pwd,ps,cd,echo,rm,rmdir,mv,mount,diff,curl,wget,cp,cat等等,并不是它真的有这些linux命令,而是用了alias,我们输入alias即可查看所有的别名

设置自己的别名举例:set-alias grep select-string。这样就可以将查找字符映射为熟悉的grep,但是怎么保存这个别名呢?

  1. 首先找到配置文件位置

    1
    echo $profile
  2. 查看配置文件是否存在

    1
    test-path $profile
  3. 新建文件

    1
    new-item -Path $profile -ItemType file -force
  4. 将配置写入文件

    1
    echo "alias grep select-string" > $profile
  5. 给权限

    1
    2
    # 查看默认权限
    PS C:\Users\narcissus> Get-ExecutionPolicy Restricted

    Restricted权限会阻止打开powershell时去读取配置文件的,所以需要修改,可以在这里查看各种权限意义

    1
    2
    # 修改权限,remotesigned会要求从网上下载的必须要签名否则不能运行,但是本机的可以
    Set-ExecutionPolicy -ExecutionPolicy RemoteSigned

    The acceptable execution policy values are as follows:

    • AllSigned. Requires that all scripts and configuration files are signed by a trusted publisher, including scripts written on the local computer.
    • Bypass. Nothing is blocked and there are no warnings or prompts.
    • Default. Sets the default execution policy. Restricted for Windows clients or RemoteSigned for Windows servers.
    • RemoteSigned. Requires that all scripts and configuration files downloaded from the Internet are signed by a trusted publisher. The default execution policy for Windows server computers.
    • Restricted. Doesn’t load configuration files or run scripts. The default execution policy Windows client computers.
    • Undefined. No execution policy is set for the scope. Removes an assigned execution policy from a scope that is not set by a Group Policy. If the execution policy in all scopes is Undefined, the effective execution policy is Restricted.
    • Unrestricted. Beginning in PowerShell 6.0, this is the default execution policy for non-Windows computers and can’t be changed. Loads all configuration files and runs all scripts. If you run an unsigned script that was downloaded from the internet, you’re prompted for permission before it runs.
  6. 然后就可以随意使用grep了

自定义初始化路径

每次打开powershell的时候,目录都不在home目录,想修改为home目录

1
echo "cd $home" >> $profile

pipe

可以将前一个命令的输出,作为后一个命令的输入。不同于linux的shell,powershell的所有输出都是对象,而在控制台显示的信息仅仅是对象的一部分信息,那么可以通过调用对象的方法来查看更多信息。

-inputobject获取到对象

$_代表传递过来的默认变量(对象)

1
2
# 查看每个进程名以及所属公司:ps通过管道过来的数据都是对象,直接使用ps是看不到这些数据的,但是可以通过对象得到这些数据
ps | echo -InputObject {$_.ProcessName + '-->' + $_.Company}

变量

类似于perl,变量声明需要在变量名前加$,变量的引用同样需要$

例如配置文件:$profile

通过pipe传递过来的变量默认为$_get-item ./* | foreach {write-output $_; sleep 1}

字符拼接:+

string

字符串具有许多的方法

1
2
3
4
5
$a = (ipconfig)
$a.replace('0',1)
$a.split('.')
$a.count
$a.length

输出,支持颜色

1
write-host $a -backgroundcolor black -foregroundcolor white

数组

1
2
3
4
$list = @(1,2,3,4)
$list = 1,2,3,4
$list = 1..4
write-output $list

我们知道在powershell中一切都是对象,那么数组就具有很多方法和属性可调用

1
2
3
4
5
6
7
8
$p = @(get-process)
$p.count
$p.length
$p[index]
$p[1]
$p[1] = '0'
$p.contains(0)
$p -notcontains(1)

这种方式创建的array无法修改$list.isfixedsize为True

1
[system.collections.arraylist]$list = 1..5

这样创建的就是可变长度的list

1
$list.remove(5)

hash

1
2
3
4
5
6
7
8
9
$hash = @{'A'=1; 'B'=2; 'C'=3}
$hash['A']
$hash.count
$hash.keys
$hash.values
$hash.containskey('A')
$hash.containsvalue(2)
$hash.remove('C')
$hash['C'] = 3

循环

  • while
  • for
  • foreach
1
2
3
4
5
6
7
while (condition){

}
# 或者
do {

} while (condition)
1
2
3
for (condition){

}
1
2
3
foreach (condition){

}

举例:

1
2
3
4
5
$i = 0
while ($i -lt 5){
write-output $i
$i++
}
1
2
3
for ($i=0;$i -lt 5;$i++){
write-output $i
}
1
2
3
foreach ($file in (get-item ./*).fullname) {
write-output $file
}

条件

1
2
3
4
5
6
7
8
9
if (condition){

}
elseif (condition){

}
else{

}

数字与字符比较都用-eq -gt -lt等等。不过字符比较时默认忽略大小写,如果要考虑大小写添加-c

1
if ('ABC' -ceq 'Abc'){echo 1}

逻辑运算:-and -or -not

1
if (2 -gt 1 -and 3 -lt 4){echo 'ok'}

函数

1
2
3
4
function FunctionName (parameters)
{
#script block
}

异常

1
2
3
4
5
6
7
8
9
10
11
12
13
try {
Remove-Item "C:\doentexist\file.txt" -ErrorAction Stop
}
catch [System.Management.Automation.ItemNotFoundException] {
Write-Host "item not found" -ForegroundColor red
}
catch {
Write-Host "undefined errors" -ForegroundColor orange
Write-Host $error[0] -ForegroundColor orange
}
finally {
"Finally block"
}

取消终端输出

不像在linux可以重定向到/dev/null,powershell中是输出给到out-null

1
2
3
[system.collections.arraylist]$list = @()
# list在添加值的时候会输出index,为了不输出可以这么做
$list.add(1) | out-null

其实还可以将输出赋值给一个变量

1
$null = ($list.add(1))

格式化输出

1
2
3
get-childitem | format-table
get-childitem | format-list
get-childitem | format-wide

正则表达式

1
2
# 会返回True/False
[regex]::isMatch($i,"txt")
1
2
# 获取当前路径下txt文件,虽然可以用get-item *txt
foreach ($i in (get-item ./*).Name){if ([regex]::isMatch($i,"txt") -eq 'True'){echo $i}}

常用命令

select-string 匹配

stop-computer 关机

实例

1
2
3
4
5
6
7
8
# 查看每个进程名以及所属公司:ps通过管道过来的数据都是对象,直接使用ps是看不到这些数据的,但是可以通过对象得到这些数据
ps | echo -InputObject {$_.ProcessName + '-->' + $_.Company}

# 查看进程数:ps命令是没有count参数的,但是其输出对象有这个方法
echo (ps).count

# 每个一秒逐行打印文件数据
cat .\cmd.txt | foreach {echo $_;sleep 1}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 下面这个就是实现给定条件文本,然后在许多文件中去找是否存在,对存在的数据进行复制。类似与linux的grep|cp的组合功能
# 需要对没有搜索到的条件进行打印,这个确实有点难,因为不是每个文件都包含这个条件,那么循环中既有找到的,也有找不到的
# 其实只要对找得到的,找不到的都做一个标记,将结果放进一个集合,然后找一个找到标记都没有的,那就是真的找不到的
# 将内容保存为search_txt.ps1,然后就可以直接在powershell中直接调用了,很方便

# 定义条件的文本
$condition = 'cmd.txt'
# 定义复制到哪的路径
$destition = '~/Desktop/new'

foreach ($con in (get-content $condition)){
[system.collections.arraylist]$list = @()
# 将文件夹,及不需要搜索的文件加入-exclude后面,逗号分隔
foreach ($file in (get-item ./* -exclude 'new','install.sh').fullname){
if ((select-string $con $file).count -gt 1){
$null = $list.add('ok')
copy-item $file $destition
}
else {
$null = $list.add('no')
}
}
if ($list.Contains('ok')){
}
else{
# 输出未找到的条件
write-host [$con] not find in files -BackgroundColor DarkCyan
}
}

总结

powershell学习起来比linux shell简单多了,因为所有命令都是通过verb-noun这种方式来表示的,可以很轻易的查到。另外所有命令都有使用例子,真的很简单。虽然命令很多,但是却可以现学现用。如果花与学习linux shell相同时间,powershell一定玩的很溜,但是我不学了,好累突然。哈哈,我觉得我学的已经可以了,写个脚本什么的没问题了。反正一切皆对象,只要是同一类对象,根本就不用去记忆,直接调用就行了,反正方法都一样。现在想想大二时候刚开始学电脑的我,那个时候的我觉得这个东西太难了,学的也很慢,而且没学懂,变量都不会用。所以说学习的确是一个厚积薄发的过程,只有不断的学习新东西,学到更多的东西,才会越来越觉得简单。真的现在看到群里那些小伙伴提的问题我觉得好简单啊,虽然有很多不会的东西,但是去百度搜一下,然后就可以直接拿来用了,毫无违和感。我又飘了!

突然收到一条短信,我收到快递了,可是我没买东西,我发现这是一个最可怕的东西,该来的还是来了