命令行

作者: bowen_wu | 来源:发表于2022-08-11 10:05 被阅读0次

概述

  • kernel => 内核 => 负责和硬件交互
  • Shell => 壳 => 和 kernel 交互 => 广义的 Shell 包含一切通过字符终端控制计算机的方式
    • Windows => cmd/PowerShell/Git bash
    • UNIX/Linux => sh/zsh/Terminal

本质

  • 命令行/终端的本质是一个进程
  • 在服务器上 cat /etc/passwd => root:x:0:0:root:/root:/bin/bash => 最后的 /bin/bash 就是登陆了之后运行哪个程序
  • 读取你的输入,并且做出反应
    • 内置命令,直接执行
    • 查找 $PATH 中对应可执行程序并将参数传递给它
    • 如果是 exit,终止自己
  • 大多数情况下,执行一个命令 == fork 一个新的进程
    1. source => 在当前 shell 中执行
    2. exec => 将 fork 的进程替换为参数的进程 => exec echo "123" => 暴力的将当前进程替换为 echo 进程

命令的四要素

  • 如果四要素完全相同,那么命令一定可以重现
  • 如果命令出现诡异问题,那么一定是四要素之一发生了改变
  • 四要素
    1. Executable => 可执行程序
    2. Arguments => 参数
    3. Working Directory => 工作路径
    4. Environment Variable => 环境变量

Environment Variable

  • 和进程相绑定的一组键值对
  • 所有的操作系统都支持 => Windows 上不区分大小写
  • 所有的编程语言都提供原生支持
  • 派生的子进程都会继承父进程所有的环境变量 => 不能逆向传递
  • Java 命令会读取 CLASSPATH 环境变量,作用相当于 -cp
  • 快速传递一个环境变量 => AAA=2 source 1.sh => 1.sh(echo $AAA)

Executable

  • 可执行程序
    • Windows => exe/bat/com
    • UNIX => +x
  • Shell 如何找到可执行程序
    1. 内置命令
    2. alias
    3. $PATH
    4. Windows 会在当前目录里找

分类

  1. 二进制可执行程序 => 符合对应操作系统的要求,能够直接执行,无需解释器 => file jdk-11.0.13.jdk/Contents/Home/bin/java => jdk-11.0.13.jdk/Contents/Home/bin/java: Mach-O 64-bit executable x86_64
  2. 脚本 => 在第一行指定解释器(shebang) => #!/usr/bin/env xxx(在当前环境变量中查找 xxx 程序) => 等同于 xxx <file>.sh

Arguments

  • 参数完全由对应的可执行程序负责解析
  • Shell 操作参数
    1. 通配符展开(globbing)
    2. 变量展开 => Shell 中的变量($) & $() & ``
    3. 双引号会进行变量展开,单引号不会
  • Shell 获取参数 =>
    1. $0 => command
    2. $1 $2 $3 ...
    3. $@ 将所有参数装配成数组

Working Directory

  • 启动命令的路径 => pwd => print working directory
  • 相对路径都是相对于这个路径
  • Java => new File(".") 代表相对当前目录的路径

标准输入 & 标准输出 & 标准错误

  • 文件描述符 => file descriptor
  • 标准输入 stdin => fd=0 => 使用 < 或者 <<
    1. 使用 < 从文件读取数据输入给进程(不一定要是字符) => grep 4 < 1.txt(在 1.txt 中查找4)
    2. 使用 << 输入块数据
  • 标准输出 stdout => fd=1 => 使用 > 或者 >>
  • 标准错误 stderr => fd=2 => 使用 2> 或者 2>>
  • 标准输出和标准错误输出到同一文件 => <command> > output.txt 2>&1
  • UNIX 垃圾桶 => <command> > output.txt 2> /dev/null

管道

  • 连接标准输出和标准输入,将上一个进程的标准输出作为下一个进程的标准输入
  • ls | grep class | wc -l => word count -line
  • cat 1.txt | grep 3 | xargs touch
  • echo ${PATH} | cut -d ':' -f 5
  • ps aux | grep java | awk '{print $2}' | xargs kill -9

重定向

  • mvn -X compile | tee output.txt
tee

Shell 返回值

  • echo $? => 获取上一个进程的返回值
  • 每个进程都有返回值
  • 0 => success
  • 非0 => fail

在 Java 程序中启动和执行命令

  • java 命令 => java <JVM 启动参数> <Main类> <传给 Main 类的参数>
  • Shell 传递的参数会进入 String[] args
  • 环境变量 => System.getenv("AAA"); => 只能读不能写
  • System Property(系统属性)只有 JVM 支持 => System.setProperty("BBB", "111"); System.getProperty("BBB"); => 可读可写
  • -Dfile.encoding=UTF-8 => 指定了系统中默认的编码
JVM Default System Property

Java 程序 fork 一个新进程

import java.io.BufferedReader;
import java.io.InputStream;

public class ForkProcess {
    public static void main(String[] args) {
        // 获取当前项目的 git log 数据
        // executable git
        // arguments log --oneline
        // environment variable
        // working directory
        ProcessBuilder pb = new ProcessBuilder("git", "log", "--oneline");
        // pb.inheritIO().start();
        Process process = pb.start();
        InputStream inputStream = process.getInputStream();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, Charsets.UTF_8));
        String line;
        while ((line = bufferedReader.readLine()) != null) {
            System.out.println(line);
        }

        pb.environment().put("AAA", "111");
        ProcessBuilder pb = new ProcessBuilder("ls", "*"); // Error。此时 * 不会进行通配符展开,通配符展开是 bash 的行为
        ProcessBuilder pb = new ProcessBuilder("bash", "-c", "ls *");
        ProcessBuilder pb = new ProcessBuilder("ls", "`pwd`/.."); // Error
        ProcessBuilder pb = new ProcessBuilder("ls", "|", "wc", "-l"); // Error
    }
}

输入输出重定向

  • 可能需要额外的线程
  • 如果 fork 的进程需要输入才能输出,那么 JVM 和 fork 的进程不能同时进行读写,需要创建一个 write 线程去负责输入,之后 JVM 才能正确读取 fork 进程的输出

知识点

  1. CR/LF => CarriageReturn/LineFeed
  2. OS(操作系统) => 抹平了硬件的差异
  3. POSIX标准
  4. PS1 => terminal 的前缀提示符 Personal-Laptop-14 at ~ ❯ => echo $PS1
  5. bash doc
  6. bash -x <command> => 将命令内部的执行过程打印出来用于排查

相关文章

  • MAC命令行

    命令行命令行

  • 常用命令行

    命令行中英文对照 命令行缩写 常用命令行 如何使用 explainshell.com 这个网站 网站链接:命令行释...

  • 命令行开启、关闭adb

    命令行开启adb: 命令行关闭adb:

  • 命令行

    基本命令行: 文件路径命令行:

  • 开发常用命令

    命令行启动服务 命令行启动activity 命令行发送广播 monkey启动应用 java打堆栈

  • 2018-12-20

    lolcat 彩色命令行cowsay 命令行加动物

  • Linux 3.bash

    命令行跳转:Ctrl+a:跳到命令行首Ctrl+e:跳到命令行尾Ctrl+u:删除光标至命令行首的内容Ctrl+k...

  • 初识命令行之ls cat mv touch

    目录:一. 如何查找命令行的常见用法二. 几个命令行的常见用法三. 如何查找命令行释义 一.如何查找命令行的常见用...

  • #python入门1#入门

    终端进入命令行模式 python 命令行退出终端 exit() 命令行执行.py脚本 python hello.p...

  • 命令行基础

    命令行基础 命令行是什么? 命令行界面(command-line interface), 缩写CLI, 是在图形用...

网友评论

      本文标题:命令行

      本文链接:https://www.haomeiwen.com/subject/hznywrtx.html