入门、历史与启动

Kernal与Shell

  • Kernal指的是内核,对于linux而言就是负责与计算机硬件交互的底层代码,例如cpu调度
  • Shell是指代表用户与内核程序交互的程序

    广义命令行

  • 广义命令行是指一切通过字符终端控制计算机的方式

    • Windows - cmd\Powershell\Git bash
    • Linux - sh\zsh\Teminal

      为什么使用命令行

  • 几乎所有的公司的服务器都运行在Linux上

  • 运行在Linux上可以将工作自动化,自动化是一切生产力的根源(比手工操作更有效率)
  • 相比GUI,命令行更容易开发维护,bug更少
  • 远程连接占用更低的资源
  • 命令行上生产力开发者工具更丰富

    启动进程的四要素

    可执行程序 Executable

  • 可执行程序就是命令行结构中的第一个单词

  • Windows系统中,会自动补全exe\bat\com等后缀名
  • 操作系统检索可执行程序所在目录的方式如下
    • WIndows:Path(path)环境变量 + 当前目录
    • 输入命令后会在PATH环境变量中依次查找(echo $PATH),找到后(which java)启动,注意Linux不会在当前目录中进行查找,可以使用 ./main 来执行当前目录下的main程序
  • linux中,每个文件都有r(read)w(write)x(executable)三种权限,如果有x权限,就被视为可执行程序,windows由其扩展名exe决定
  • 可以在文本文件中写若干个操作,再给文件加上可执行权限,实现自动化操作,甚至可以使用脚本语言(不用shell命令),只要提前指定脚本语言解释器(shebang)即可,例如

    1. #!/usr/bin/env node (从环境找node,推荐做法)
    2. #!/usr/local/bin/node (通过绝对路径找node)
    3. console.log(123)
    4. console.log(456)
  • 别名alias,常用较长的命令可以指定别名,以提高工作效率,别名与环境变量一样,只影响当前上下文,如果要设置为全局,与设置全局环境变量一样,在bash_profile文件配置

    1. alias gs = 'git status'

    参数(易错)

  • 参数在终端是不被处理的,找到可执行程序后,参数全部传递给可执行程序,参数的解释由该程序负责处理

  • Unix 参数约定如下(有些程序不遵守):使用单横杠 用单个字符表示一个参数(可合并),使用双横杠 后可接单词表示一个参数 例如,git push -f与git push —force相同,但java并未遵守该约定
  • 通过字符串可以将参数划归为一个,实现在长参数中加空格,但是有坑,例如$符号会将环境变量展开,但写在字符串则不会,注意双引号则不行,双引号会展开$变量
  • 如果要传递单引号,可以使用转义或者外面包括双引号
  • 命令行会展开*号(常用通配符)

    环境变量 Environment variable

  • 计算机中最小的工作单元是一个进程,进程占用独立的内存空间和资源,每个进程都和一组变量相绑定

  • 环境变量就是存在于一个环境的键值kv对,影响所有从该环境中启动的程序的行为,传递不同的环境变量可以让程序表现出不同的行为
  • 进程是由父进程派生fork,对于linux,其启动时会从init进程派生出一个进程树,而环境变量是会被逐级继承的(进程树)

命令行详解 - 图1

  • 环境变量被所有操作系统以及各种程序语言编写的程序支持,常在软件工程中作为共享配置数据,在进程间相互传递,因此环境变量是一种通用的在进程中传递变量、配置的一种方式
  • 所有编程语言均内置了对环境变量的访问等
  • 环境变量是有作用域的,甚至可以对一个进程有效,例如 myname=1 go run main.go
  • 可以配置局部和全局环境变量,例如需要一个变量在所有bash中生效,可以在bash_profile文件配置
  • docker容器是一种特殊的进程,其环境变量不收外部环境的影响,需要显示的进行传递环境变量
  • 环境变量可通过export(linux)\ set(windows)设置,通过echo读取

    1. export AAA='$A;'
    2. echo $AAA

    工作目录 Working directory

  • 启动命令的路径(光标闪烁的位置)

  • pwd 查看当前工作目录
  • 绝对路径 从根目录开始的路径
  • 相对路径 相对于当前工作目录的路径

    进程启动后影响其的三要素

  • 输入和输出影响的是和进程打交道的方式

    标准输入 stdin

  • 例如输入的操作字符

image.png

标准输出 stdout

  • 文件描述符为1
  • 标准输出采用管道1输出 java Main 1> output.txt (默认的)

    标准错误 stderr

  • 文件描述符为2

  • 标准错误采用管道2输出 java Main 2> output.txt

    输出的重定向

  • java Main > output.txt 当前进程标准输出覆盖到文件

  • java Main >> output.txt 当前进程标准输出追加到文件
  • java Main > output.txt 2>&1 当前进程标准输入输出覆盖到文件,过程是先将标准错误重定向到输出,再输出(从右向左)

    垃圾桶

  • /dev/null

    常用命令

  • cd(change directory) 进入(改变)目录

    • cd . 当前目录
    • cd .. 上一级目录
  • ls(list)显示当前目录中的非隐藏目录
    • unix约定以点(.)开头的为隐藏目录,例如.ssh
    • ll 显示文件详细信息 ls -l
    • ls -alth 所有文件\详细信息\修改时间倒序\人类可读
  • mv(move) 移动、重命名文件
  • rm(remove) 删除文件
    • rm -r 迭代删除文件(所有子树)
    • rm -rf 强制删除
  • cp(copy) 拷贝文件
    • cp -r
  • echo 输出一个内容
    • 常用于显示变量(当前环境)
    • 快速创建文件 echo 123 > file.txt
  • export
    • 导出变量(向当前环境),使得当前环境启动的后续进程均拥有该变量
  • git pull\push\add\commit... git系列操作
  • mkdir 新建目录
    • mkdir -p a/b/c/d
  • pwd (print working directory)显示当前目录全路径
  • cat 显示文件
  • vi 编辑文件
  • source 文件生效
  • alias 为命令指定别名(输入完当前环境生效)

    使用命令行编译运行java程序

  • 在带有图形化界面的IDE中的操作,本质上均在拼接命令行操作

  • java main函数的参数string[] args就是从命令行中读取类名后面的参数并传进来
  • 系统属性可以看作是jvm中的环境变量(仅在jvm中生效),用于在启动时向jvm传递参数
    • java中获取环境变量 System.getenv(“AAA”)
    • java中获取预定义的系统属性System.getPropert(“java”)
    • 向传递系统属性的方式 java -Dfile.encoding=UTF-8
  • mvn本质是一个脚本,负责启动一个jvm,所以-D也可以向mvn传递参数

    1. mvn install -Dmaven.test.skip=true
  • java命令后跟的参数,以类名为分界,左侧都是传给jvm自己的参数,右侧是传给java程序的参数,例如classpath也是传递给jvm的参数,多参数值用:进行分割(windows用分号;)

    1. // jar就是个压缩包,存放第三方类,使用classpath 传递jar包引入第三方类库
    2. // classpath 可简写为cp,需要的类可以用冒号:分割
    3. javac -classpath commons-lang3-3.9.jar StringIsBlank.java
    4. java -classpath commons-lang3-3.9.jar:. StringIsBlank "" " " "*"
    1. //测试程序
    2. public class Main{
    3. public static void main(String[] args){
    4. System.out.println("args: " + java.util.Arrays.toString(args));
    5. System.out.println("env: " + System.getenv("AAA"));
    6. System.out.println("system property: " + System.getProperty("AAA"));
    7. System.out.println("java version: " + System.getProperty("java.version"));
    8. System.out.println("user.dir: " + System.getProperty("user.dir"));
    9. }
    10. }

    Java中fork(派生)子进程

  • 进程启动的四要素

    1. 可执行程序
    2. 参数
    3. 工作目录
    4. 环境变量
  • 该方法的优点
    • 用java实现自动化跑脚本
    • 实现动态参数的脚本
    • 完成当前进程无法做到的工作,不得不fork一个子进程 ```java package com.github.hcsp.shell;

import java.io.File; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Map;

public class Fork { public static void main(String[] args) throws Exception { // 请在这里使用Java代码fork一个子进程,将fork的子进程的标准输出重定向到指定文件:工作目录下名为output.txt的文件 // 工作目录是项目目录下的working-directory目录(可以用getWorkingDir()方法得到这个目录对应的File对象) // 传递的命令是sh run.sh // 环境变量是AAA=123 ProcessBuilder pb = new ProcessBuilder(“sh”, “run.sh”); pb.directory(getWorkingDir()); Map envs = pb.environment(); envs.put(“AAA”,”123”); pb.redirectOutput(getOutputFile()); pb.start().waitFor(); }

  1. private static File getWorkingDir() {
  2. Path projectDir = Paths.get(System.getProperty("user.dir"));
  3. return projectDir.resolve("working-directory").toFile();
  4. }
  5. private static File getOutputFile() {
  6. return new File(getWorkingDir(), "output.txt");
  7. }

}

```

运用命令行安装Maven

  • maven一个版本可在多个机型上使用,因为其本质是在使用java,包含各系统可使用的maven程序
  • linux再当前环境增加环境变量 export PATH = $PATH:/c/Users/xxx/Downloads/apache-maven-3.6.1/bin,再echo $PATH查看是否成功
  • 若要在bash进程永久生效,需要更改bashrc文件
  • maven -v查看版本

    学好命令行的路线

  • ⾃⼰对着书敲命令

  • 尽可能地在开发中使⽤命令⾏
    • vi/git/mkdir, etc.
  • 使⽤命令⾏的各种⼩⼯具
  • 开发命令⾏的程序
  • ⾃⾏在云服务器上开发部署博客
  • ⾃⾏在云服务器上进⾏持续集成实战
  • ⽇常使⽤Linux进⾏开发

    shell语法

  • $表示展开变量

  • 表示注释

  • ./可执行文件 可以执行当前目录下的可执行程序
  • ‘’单引号包括字符串表示其中内容原样输出,而双引号会展开其中变量,或者使用转义\
  • *表示通配符,会被展开