为什么要学命令行?
如果你是一个小白,学习命令行,可以让你入睡。- 如果你是一个电脑玩家,学习命令行,可以让你
装逼事半功倍。
啥是命令行
大家经常使用的叫做图形界面(GUI)。
而命令行就是形如下面的字符界面(CUI,CLI):
▲Command-Line Interface, 图示为PuTTY
- Windows工具为CMD,PowerShell,Windows Terminal
- *nix类系统上为Bash
- Mac上则为Zsh(之前也为Bash),终端
不管是图形界面还是字符界面,其目的都是为了方便你使用操作系统。图形界面的方便在于直观,可视化。命令行的方便在于精确和掌控感。 将分别介绍Bash,CMD及Powershell。
先来区分几个概念。
脚本
脚本(script)就是存放命令的文本文件。
在*nix平台,脚本一般后缀为sh。
在Windows平台中,CMD脚本称为批处理文件,后缀为bat;Powershell脚本后缀为ps1。
Shell
shell就是脚本运行程序
也就是说,shell 用来运行脚本
- shell 可以一条一条地交互式运行用户指令(用户输一个,shell 跑一个)
- shell 也可以执行脚本中的命令 (shell 跑完一个文件中的所有命令)
- 在脚本中,可以定义函数、变量、条件判断等语句,所以写脚本也是编程
终端,Terminal
终端是上古电脑的一个概念。以前电脑都是用于科学计算,所以一个主机会分出多套屏幕键盘和鼠标。这一套套键鼠屏幕,构成了一个终端。
所谓终端,就是使用计算机的客户端。
现在的终端已经变成了一个程序,用来容纳shell。比如SSH、Windows Terminal,以及macOS的终端
。
命令行基本语法
无论是Bash,CMD抑或是Powershell,命令的基本结构都是:
command option # 也就是: 命令+选项参数
command可能是:
1、shell内置命令,比如Bash的cd
2、系统提供的程序/脚本,linux中,这些程序通常存在于/bin
,/usr/bin
目录中
3、外部程序:工作目录中的脚本(用户手写/下载)和二进制程序、PATH变量中的程序
只要把程序放在PATH变量对应的目录中,程序就可以直接在shell 中运行,
否则,你就需要输入程序的完整路径才能运行。
option是选项/参数
它是用于修改、确定command行为的。option可以很简单,简单到可以省略不写;也可以非常复杂,复杂到阅读起来很吃力。
ls #显示目录内文件
ls -l #显示目录内文件的详见信息,包括日期、大小
firewall-CMD --permanent --zone=public --list-ports
总之,在shell中,你可以运行各种程序,还可以通过各种参数控制程序行为。
Bash/Zsh - *nix 下的命令行
替换
替换是非常重要的命令行概念,在执行命令前,先将部分命令替换成值或结果
,然后执行命令。这里以*nix为例,CMD 和PS 也有替换的概念。
比如说,你需要多次使用iPhone
的名称,但是你觉得打字不太方便,你就可以把这窜字符存到变量中:sj=iPhone
。等你下次需要使用,比如在窗口打印“iPhone”字符的时候,可以直接敲打命令:echo $sj
。
用变量的值替换变量名,这是最常见的一种替换。
变量替换
- 变量的定义为:name=value,=号旁不能有空格
- 变量的使用,需要在名称前添加美元符号:$vname (或者${vname},这个形式也非常好用)
- 变量的修改:变量名=新值,
sj=Xiaomi
使用变量时,命令在执行前,会把变量先变成变量存储的值。
address=https://manyouit.com
curl $address
执行过程:
- 先把$address 变成https://manyouit.com
- 执行
curl https://manyouit.com
变量与引号
由于Bash 中,某些字符有特殊的意思。如何使用这些特殊字符? ——使用引号。
address=https://manyouit.com
curl '$address' # 程序错误,因为没有$address这样的网址;亦即“变量替换”失效
curl "$address" # 成功;双引号不会使得“变量替换”失效
使用单引号(英文),可以使大部分特殊符号失效;使用双引号(英文),不会使特殊符号失效。
执行结果替换,命令替换
先执行内部命令,然后结果作为新命令的一部分。
两种形式:
`inner command`
$(inner command)
address=https://manyouit.com/
echo `echo $address`
$(echo $address)
CMD: REM 括号有类似功能
set a=(cmd)
数学运算与表达式替换:$(()),$[]
echo $[1+2] #3
echo $((1+2)) #3 ,$(()),$[]等效
支持+ - * / %:分别为 “加、减、乘、除、取模”等运算。但是注意,Bash只能作整数运算。
进程替换与管道
进程替换:
将(多个) 命令/进程的输出存储成文件,然后作为当前命令新的组成部分;
或者将当前命令的输出成文件,作为新命令的输入。
文件替换
$(<filename)
`<filename`
读取文件内容组成新命令 。
替换:变量 vs 命令 vs 文件 vs 进程 vs 管道
# 变量替换:先取变量值,用值重新组成命令后执行。
echo ${PATH#*:} # 变量值替换(不修改变量本身),此处使用模式 *: 移除变量中部分
# 命令替换:先执行内部命令,用执行输出内容重新组成命令后执行。
ls -ld `locate which` # ls -ld $(locate which) 这种方法兼容性较差。
# 进程替换:先执行部分命令,用执行输出内容成文件后,**文件名**重新组成命令后执行。
comm <(ls -l) <(ls -al)
cat a.txt >(cat >b.txt)
# 文件替换:先读取文件内容,用读取的内容重新组成命令后执行。
# 管道: 前一个命令执行的`stdout 成为后面命令的stdin`
CMD1 | CMD2 | CMD3
PowerShell - 微软新一代命令行
值
字面值:
- 数字:
123
- 字符串:
"good"
,'she says, "amazing"'
- 对象
输出值:
对于数字和字符串,在命令行处直接输入值,然后Enter即可输出
对于变量,在命令行处直接输入值,然后Enter即可输出
用逗号来输出多个值,每一个值都会还行显示:$a,3
变量,美元字符开头$Var1
声明变量:
$Var1="good #等于号之前允许一个空格"
或者
$aNumber = 5 -as [double]
$aList = 1,2,3,4,5
$aString = $aList -join '--' # 也可以用-split来分离
$aHashtable = @{name1='val1'; name2='val2'}
echo $aString
echo "Interpolation: $aString" #双引号内可以解析变量
echo "$aString has length of $($aString.Length)" #变量可以包括在$()中,$()用来解析变量
echo '$aString' #单引号内不可以解析变量
echo @"
This is a Here-String
$aString
"@
# 双引号 Here-String 及解析变量
# 可以用单引号来声明Here-String ,此时无法解析变量
变量和赋值=顺序,$a=CMD argu… 先执行再赋值
CMD - 微软上一代命令行
CMD
程序中文名称为命令提示符
。它的脚本文件格式为.bat
,也称批处理。
变量与%(百分号)
%变量%
,会把变量的结果作为命令的一部分,(类似Bash 变量替换)- 在命令行界面和批处理文件(.bat 后缀文件)里,变量形式为
%Name%
- 在for 语句中的临时变量
- 命令行用
%Name
- 批处理文件用
%%Name
- 命令行用
- 特殊表示,在批处理文件中%0-%9 用来处理程序的参数输入
对比与区别
命令组合、分隔符
对*nix 有效
command1 ; command2 #不管command1是否执行成功都会执行command2;顺序执行
command1 && command2 #只有command1执行成功后,command2才会执行,否则command2不执行
command1 || command2 #command1执行成功后command2 不执行,否则去执行command2
对Powershell 有效
command1 ; command2 #顺序执行
(command1) -and (command2) #相当于*nix 的 &&,但只能输出错误和Bool值,没有命令输出
(command1) -or (command2) #相当于*nix 的 ||,但只能输出Bool值
对CMD 有效
:: 顺序执行
command1 & command2
:: 执行成功才执行
command1 && command2
:: 执行失败才执行
command1 || command2
:: 包裹命令
(command1)
::逗号、分号相当于空格:`dir,c:\ `
::一个命令需要使用过个参数运行多次,则使用:
dir C:\;D:\
变量与环境变量,*nix与Windows
列出当前shell(继承/复制自系统)的环境变量
系统和Shell | Linux *sh | Windows CMD用户 | Windows PowerShell用户 |
---|---|---|---|
示例 | env |
set |
ls env: |
在nix环境下,set会输出当前shell 的设置。
在Linux/macOS环境下,env还有设置变量并运行的作用
创建当前shell的环境变量并暴露给子shell:
系统和Shell | Linux *sh | Windows CMD用户 | Windows PowerShell用户 |
---|---|---|---|
示例 | export x=v |
set x=v |
$env:x="v" |
说明 | export 的作用是将变量暴露给子shell | cmd中set设置的环境变量自动暴露给子shell | $env:xxx设置的环境变量自动暴露给子shell |
注意powershell 中也有set命令,它的语法是set xname xvalue
powershell 的set设置的是当前shell 的变量,不会暴露给子shell。
创建当前shell的环境变量并不暴露给子shell:
系统和Shell | Linux *sh | Windows CMD用户 | Windows PowerShell用户 |
---|---|---|---|
暴露 | export x=v |
set x=v |
$env:x="v" |
不暴露 | x=v |
undefined | set x v $x=v |
上两种创建环境变量不会修改系统级别或者用户级别的环境变量。
删除当前shell的环境变量
系统和Shell | Linux *sh | Windows CMD用户 | Windows PowerShell用户 |
---|---|---|---|
推测会暴露给子shell | unset x= |
set x= |
$env:x="" |
修改系统环境变量
系统和Shell | Linux *sh | Windows CMD用户 |
Windows PowerShell用户 |
---|---|---|---|
示例 | - |
setx x v |
setx x v |
说明 | undefined | setx 会写入注册表 | setx 会写入注册表 |
修改系统环境变量后,重新打开新shell方可观察变化。
列出shell中的单个变量或者环境变量
系统和Shell | Linux *sh | Windows CMD用户 |
Windows PowerShell用户 |
---|---|---|---|
shell内定义的 | echo $x |
echo %x% |
echo $x |
继承自环境的 | printenv PATH |
set x |
echo $env:path |
说明 | export x=v 这种变量可以 printenv x |
不区分来自环境还是内部。 可互换 |
- |
注释方法
注释是一种对脚本的标注。
行首注释需要将注释符号放在行首。
CMD/bat的行首注释形式:
rem 注释注释
或另一种:
:: 注释注释
行内注释,注释符号不需要放在行首。
CMD/Bat的行内注释形式:&:: 行内注释
Bash使用“#”符号注释:# 注释注释
PowerShell:# 注释注释
文档:<# 注释注释 #>
换行输入命令
命令太长时,容易造成阅读障碍,比如创建任务计划的触发器时:
trigger = New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval (New-TimeSpan -Minutes 5) -RepetitionDuration (New-TimeSpan -hours 24)
确实,难以阅读与理解,而只要在行末,添加`
就能实现换行输入命令:
$trigger = New-ScheduledTaskTrigger `
-Once `
-At (Get-Date) `
-RepetitionInterval (New-TimeSpan -Minutes 5) `
-RepetitionDuration (New-TimeSpan -hours 24)
行末添加的符号为转义字符
,它可以改编字符原来的意思。在这里,输入转义符好后,再键入Enter键,会产生一个新行
,但执行的时候,实际上换行
会被当成空白
。
Powershell的换行转义符为`
,另外,CMD的转义符号是^
,*nix是\
。
常用命令
常用*nix命令
lsof -i:10086 #[查看端口占用](https://linux.cn/article-4099-1.html):
ln Source Link #制作连接
netstat -anp|grep 80 #端口占用
perl -p -i -e "s/\r//g" filename #删除CR(Windows换行符有CRLF)
# 查找命令位置
which
# CentOS系统
# 防火墙:firewalld
# 设定开机启动、禁用防火墙
systemctl enable firewalld
systemctl disable firewalld
# 开启、关闭防火墙
systemctl start firewalld
systemctl stop firewalld
# 检查状态:
firewall-cmd --state
# 设定:https://www.jianshu.com/p/411274f96492
port=1313
firewall-cmd --permanent --add-port=$port/udp
firewall-cmd --permanent --add-port=$port/tcp
# 常用
firewall-cmd --permanent --query-port=80/tcp
# 列出打开端口,查看端口占用
firewall-cmd --list-ports #--permanent --zone=public
firewall-cmd --reload
常用Windows命令(此处为PS注释法)
findstr #查找字符串
nslookup -qt=A manyou.it ns-uk.topdns.com #DNS解析
powercfg -devicequery wake_armed #查看唤醒电脑的硬件
nslookup baidu.com 240C::6644 #使用特定服务器解析域名
# 设置代理:
set HTTP_PROXY=192.168.0.7:1080
set HTTPS_PROXY=192.168.0.7:1080
# 查找命令位置
where.exe
# 防火墙禁止访问(PS 写法)
netsh advfirewall firewall add rule name="IP Block" `
dir=out `
interface=any action=block remoteip=20.84.22.197,104.18.156.232,104.18.157.232,2606:4700::6812:9de8,2606:4700::6812:9ce8
# 查看hardlink
fsutil.exe hardlink list path\to\file
PowerShell命令
# 查找命令位置
Get-Command
echo $PSVersionTable #PS版本
certutil -hashfile #计算md5
Get-ScheduledTask | where {$_.settings.waketorun} #查看唤醒电脑的计划任务
Netstat -ano|findstr "8080" #查看占用某个端口的进程
Get-Command -Module PSScheduledJob | Group-Object Noun #[分组](https://www.pstips.net/about-scheduledjob.html#comment-18118),获得命令,然后分组(on Noun)
[console]::beep(500,300) #蜂鸣
set #设置变量值与cmd 同名但不同程序
New-Item -ItemType SymbolicLink -Path "Link" -Target "Source" # 创建文件的符号链接,需要管理员, 简写ni
ni -ItemType hardlink "X:\music\fav\美若黎明.flac" -target "X:\music\李健 - 李健 2015 - FLAC\02. 美若黎明.flac"
# 复制文件到目录
Copy-Item "C:\Wabash\Logfiles\mar1604.log.txt" -Destination "C:\Presentation"
CMD 命令
::打印所有变量;设置变量值
set
::查找程序位置
for %i in (cmd.exe) do @echo. %~$PATH:i
::windows地址栏使用`\`而不是`/`
::制作目录软连接:
mklink /D Link Source
::制作文件软连接
mklink Link Source
三方程序记录
# frp
./frps -c ./frps.ini #有标准输出
nohup ./frps -c ./frps.ini &
pip install --upgrade name # 更新pip包
java -version # 查看版本