Ubuntu安装笔记

Ubuntu18.04安装笔记

硬盘安装

easyBCD=>Add New Entry=>NeoGrub=>Install=>Configure

title Install Ubuntu
root (hd0,0)
kernel (hd0,0)/vmlinuz.efi boot=casper iso-scan/filename=/ubuntu.iso ro quiet splash locale=zh_CN.UTF-8
initrd (hd0,0)/initrd.lz

把ubuntu.iso放到C盘,并解压其中的vmlinuz.efi及initrd.lz也放到C盘

如果启动后显示File not found,可以试试把ISO文件名改短,或者把vmlinuz.efi改成vmlinuz,或者检查一下C盘是不是(hd0,0)

安装前要卸载挂载点

sudo umount -l /isodevice

修改源

ubuntu 22.04及以下版本换源,22.04的代号是jammy,其他版本自行替换:

# 先备份原来的源
sudo cp /etc/apt/sources.list /etc/apt/sources.list.backup

# 修改源
sudo gedit /etc/apt/sources.list

# 把阿里云的源复制进去
deb http://mirrors.aliyun.com/ubuntu/ jammy main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ jammy main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ jammy-security main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ jammy-security main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ jammy-updates main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ jammy-updates main restricted universe multiverse
# deb http://mirrors.aliyun.com/ubuntu/ jammy-proposed main restricted universe multiverse
# deb-src http://mirrors.aliyun.com/ubuntu/ jammy-proposed main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ jammy-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ jammy-backports main restricted universe multiverse

ubuntu 24.04版本换源,24.04的代号是noble,其他版本自行替换:

# 先备份原来的源
sudo cp /etc/apt/sources.list /etc/apt/sources.list.backup

# 修改源
sudo gedit /etc/apt/sources.list

# 把官方的源注释掉,再把清华的源复制进去
Types: deb
URIs: http://mirrors.tuna.tsinghua.edu.cn/ubuntu/
Suites: noble noble-updates noble-security
Components: main restricted universe multiverse
Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg

清理不常用软件

sudo apt-get remove libreoffice-common gnome-sudoku aisleriot gnome-mahjongg gnome-mines deja-dup

安装常用软件

更新

sudo apt-get update
sudo apt-get upgrade
sudo apt-get dist-upgrade

sudo update-manager -c -d
do-release-upgrade

驱动安装

ubuntu-drivers devices
sudo ubuntu-drivers autoinstall

如果安装软件时提示缺失依赖,执行以下命令修复

sudo apt install -f

gedit

sudo apt install gedit

压缩工具

sudo apt install unzip
sudo apt-get install unrar
sudo apt-get install p7zip-full

图形化压缩软件

sudo apt install xarchiver

下载工具

apt-get install axel

sudo add-apt-repository ppa:t-tujikawa/ppa 
sudo apt-get update 
sudo apt-get install aria2
sudo gedit /usr/local/bin/Aria2c
# (粘贴)
aria2c --enable-rpc --rpc-listen-all --rpc-allow-origin-all  --file-allocation=none --max-connection-per-server=3 --max-concurrent-downloads=5 --continue -d ~/Downloads/

sudo chmod +x /usr/local/bin/Aria2c

zsh

sudo apt-get install zsh

# 下载 oh-my-zsh 项目来帮我们配置 zsh
wget https://github.com/robbyrussell/oh-my-zsh/raw/master/tools/install.sh -O - | sh
# 或
git clone git://github.com/robbyrussell/oh-my-zsh.git ~/.oh-my-zsh
cp ~/.oh-my-zsh/templates/zshrc.zsh-template ~/.zshrc

chsh -s /bin/zsh

创建桌面图标

新建文件XXX.desktop,内容如下

[Desktop Entry]
Version=1.0
Type=Application
Name=XXX
Icon=/usr/local/xxx.png
Exec=/usr/local/xxx
Comment=XXX
Categories=TextEditor;Development;Math;Science
Terminal=false
StartupNotify=true
MimeType=text/markdown;text/x-matlab

最后sudo mv XXX.desktop /usr/share/applications或者mv /home/xxx/.local/share/applications

美化

Albert Spotlight

sudo add-apt-repository ppa:noobslab/macbuntu
sudo apt-get update
sudo apt-get install albert

gnome-tweak-tool

sudo apt-get install gnome-tweak-tool
# 或者
sudo apt install gnome-tweaks

#Ubuntu可能已经自带gnome-shell
sudo apt-get install gnome-shell

sudo apt-get install chrome-gnome-shell

安装gnome插件

推荐的插件:TopIcons PlusNetSpeedDash to Dock (https://micheleg.github.io/dash-to-dock/download.html)

部分插件可以解压后直接放到~/.local/share/gnome-shell/extensions/下,然后按Alt+F2 r Enter重启gnome生效,如果没有生效,可以通过dconf把文件夹名加到/org/gnome/shell/enabled-extensions的key中

安装gnome主题

推荐的主题:McMojaveT4G-Shell-theme III

推荐的图标:Reversal icon themeMojave CT icons

安装gnome-shell主题前要先安装User Themes插件,或者把主题放到/usr/share/themes,图标放到/usr/share/icons

更改Grub主题,推荐Grub-theme-vimix

安装Grub主题前要先安装Grub2

sudo apt-get install grub2

# 安装默认主题
sudo apt-get install grub2-themes-ubuntu-mate

# 下载主题,将主题文件夹者复制到 /boot/grub/themes/
# 然后执行(文件夹也有可能是/etc/default/grub2)
sudo gedit /etc/default/grub
# 找到GRUB_THEME,改为
GRUB_THEME=/boot/grub/themes/my-theme/theme.txt
# 再把GRUB_HIDDEN_TIMEOUT=0注释掉

# 更新grub
sudo update-grub
# 没有update-grub命令的可以执行
sudo grub-mkconfig -o /boot/grub/grub.cfg

安装Plymouth开机动画,推荐Ubunut Spinner Logo Plymouth

# 把开机动画放到plymouth目录下
sudo mv ./my-theme /usr/share/plymouth/themes/
# 修改默认开机动画
sudo ln -sf /usr/share/plymouth/themes/my-theme/my-theme.plymouth /etc/alternatives/default.plymouth

# 或者用update-alternatives安装

sudo update-alternatives --install /usr/share/plymouth/themes/default.plymouth default.plymouth /usr/share/plymouth/themes/mytheme/mytheme.plymouth 100
# 选择要用的开机动画
sudo update-alternatives --config default.plymouth
# 更新内核
sudo update-initramfs -u

修改启动页背景(Ubuntu18.04及以前)

sudo cp pic.png /usr/share/backgrounds/

# 修改
sudo gedit /etc/alternatives/gdm3.css

#lockDialogGroup {
  background: #2c001e url(resource:///org/gnome/shell/theme/noise-texture.png);
  background-repeat: repeat; }

改为

#lockDialogGroup {
  background: #2c001e url(file:///usr/share/backgrounds/pic.png);
  background-repeat: no-repeat;
  background-size: cover;
  background-position: center; }

Ubuntu20.04的更改方法

https://github.com/thiggy01/change-gdm-background

#添加执行权限
sudo chmod 777 change-gdm-background

#运行脚本,设置壁纸路径(/path/to/image)
sudo ./change-gdm-background /path/to/image

或者 https://github.com/PRATAP-KUMAR/ubuntu-gdm-set-background

# 安装依赖
sudo apt install libglib2.0-dev-bin -y

#运行脚本
sudo ubuntu-gdm-set-background --image /path/to/image

Ubuntu22.04及以上的更改方法

22.04及以上需使用gnome插件,且卸载插件后效果会消失: https://github.com/PRATAP-KUMAR/gdm-extension

开发环境配置

JAVA

方法1:通过apt安装

sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update && sudo apt-get install oracle-java9-installer

方法2:建立符号链接(通过update-alternatives --install link name path priority命令,删除就update-alternatives --remove name path

下载JDK压缩包(Oracle JDKOpenJDK),解压并复制到/usr/lib/jvm后,然后执行

sudo update-alternatives --install /usr/bin/java java /usr/lib/jvm/jdk-22.0.2/bin/java 300
sudo update-alternatives --install /usr/bin/javac javac /usr/lib/jvm/jdk-22.0.2/bin/javac 300
sudo update-alternatives --install /usr/bin/jar jar /usr/lib/jvm/jdk-22.0.2/bin/jar 300
sudo update-alternatives --install /usr/bin/javap javap /usr/lib/jvm/jdk-22.0.2/bin/javap 300

# 设置默认jdk
sudo update-alternatives --config java

方法3:添加环境变量

sudo mkdir /usr/local/java

# 解压并复制jdk进去
mkdir ./jdk-22.0.2
tar -xzvf openjdk-22.0.2_linux-x64_bin.tar.gz ./jdk-22.0.2
sudo cp -a ./jdk /usr/local/java/

sudo gedit /etc/profile
# 在最后加上
JAVA_HOME=/usr/local/java/jdk-22.0.2
CLASSPATH=$JAVA_HOME/lib/
PATH=$PATH:$JAVA_HOME/bin
export PATH JAVA_HOME CLASSPATH


# 重启后生效,或者输入以下命令在当前命令行生效
source /etc/profile

Node.js

方法一:通过apt安装

sudo apt install nodejs
# 查看node、npm版本确认是否安装成功
node -v
npm -v

方法二:建立软链接

下载安装包,解压,然后执行

mkdir -p /opt/node/
mv ./node-v20.9.0-linux-x64.tar.gz/* /opt/node/
# 如果之前已经建立了软链接,则先删掉
rm -f /usr/local/bin/node
rm -f /usr/local/bin/npm
# 然后建立软链接
ln -s /opt/node/bin/node /usr/local/bin/node
ln -s /opt/node/bin/npm /usr/local/bin/npm

换源

# 查看当前的源,没改过就应该是官方源 https://registry.npmjs.org/
npm config get registry
# 临时换源,每条命令都要加 --registry <URL>
npm --registry <URL> install xxx
# 永久换源,要恢复就改回官方的URL
npm config set registry <URL>

# 也可以使用nrm来管理源
npm i -g nrm
# 列出所有可用的源
nrm ls
# 使用指定的源
nrm use <source_name>
# 自定义源名称和地址
nrm add <source_name> <URL>
# 删除自定义源
nrm del <source_name>
# 测试速度
nrm test <source_name>

更新Node.js和npm的版本

# 通过版本管理工具n升级,这样会同时更新Node.js和npm
sudo npm install n -g
# 查看是否安装成功
n -V
# n的命令如下
sudo n 20.9.0 #升级到指定版本
sudo n latest #升级到最新版本
sudo n lts #升级到长期支持版本
sudo n stable #升级到最新的稳定版本

# 也可以只升级npm
sudo npm install npm -g

清除缓存、模块等常用命令

# 清除npm缓存
npm cache clean -f
# 列出所有全局顶级模块
npm ls -gp --depth=0
# 清除所有全局模块(列出所有顶级模块后,排除以“/npm”结尾的npm本身的所有模块,然后执行删除)
npm ls -gp --depth=0 | awk -F/ '/node_modules/ && !/\/npm$/ {print $NF}' | sudo xargs npm -g rm

Python

Linux编译安装指定版本的Python

# 解压
sudo tar -zxvf Python-3.10.11.tgz -C .\
cd Python-3.10.11
# 通过"--prefix="指定python安装的位置
./configure --prefix=/usr/local/python3.10.11
# 编译安装
sudo make
sudo make test
sudo make install

# 如果报错,可能是编译环境没配好,尝试安装以下依赖
sudo apt-get install zlib1g-dev libbz2-dev libssl-dev libncurses5-dev libsqlite3-dev libreadline-dev tk-dev libgdbm-dev libdb-dev libpcap-dev xz-utils libexpat1-dev liblzma-dev libffi-dev libc6-dev

# 更新python默认指向
# 方法一
# 先查看目前系统默认的python
ls -l /usr/bin | grep python
# 手动建立python符号链接
sudo mv /usr/bin/python /usr/bin/python.bak
sudo mv /usr/bin/python3 /usr/bin/python3.bak
sudo ln -s /usr/local/python3.10.11/bin/python3.10 /usr/bin/python
sudo ln -s /usr/local/python3.10.11/bin/python3.10 /usr/bin/python3
# 手动建立pip符号链接
sudo mv /usr/bin/pip /usr/bin/pip.bak
sudo mv /usr/bin/pip3 /usr/bin/pip3.bak
sudo ln -s /usr/local/python3.10.11/bin/pip3 /usr/bin/pip
sudo ln -s /usr/local/python3.10.11/bin/pip3 /usr/bin/pip3
# 方法二
# 先查看系统目前已配置的可用python版本
sudo update-alternatives --list python
# 先为各版本创建符号链接(未安装的版本跳过),这里假设python安装在默认位置
# (在自动模式下,最后的数字越大,优先级越高,不过我们这里会指定默认python版本,所以数字无所谓)
sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.9 1
sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.10 2
sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.11 3
# pip同理,不过pip一般使用最高版本就可以兼容大部分情况
sudo update-alternatives --install /usr/bin/pip pip /usr/bin/pip3.10 300
sudo update-alternatives --install /usr/bin/pip3 pip3 /usr/bin/pip3.10 300
# 选择默认指向
sudo update-alternatives --config python
# 对于不再使用的版本,可以移除
update-alternatives --remove python /usr/bin/python2.7

pip2和pip3

sudo apt-get install python-pip python-dev build-essential
sudo pip install --upgrade pip

sudo apt-get install python3-pip
sudo pip3 install --upgrade pip

# 或者使用python自带的工具安装pip
python -m ensurepip --upgrade

便携版python安装(Windows)

下载embeddable版的python,该版本是便携版,不带pip,所以还要安装pip:

1、解压后进入python目录,检查python版本python --version

2、安装pip(参考):

curl -L https://bootstrap.pypa.io/get-pip.py -o get-pip.py
python get-pip.py

3、便携版的python需找到python3x._pth(x是版本号),把import site前面的#删掉,才能自动识别pip

4、如果pip还是不能运行,在python3x._pth最后加上一行Lib/site-packages

注意:便携版的python在使用pip的时候最好不要直接使用pip,而是使用python -m pip调用。

注意:如果后续移动了python文件夹的位置,python\Scripts目录下的可执行文件无法直接使用,需要指定python.exe,比如".\python\python.exe" ".\python\Scripts\libretranslate.exe" --host 127.0.0.1 --port 5000.

常用命令

# pip临时换源,每条命令都要加 -i <URL>
python -m pip install <module_name> -i <URL>
# pip永久换源,并删除缓存
python -m pip config set global.index-url <URL>
python -m pip cache purge
# 换回默认源
python -m pip config unset global.index-url
# 一些源的地址
# https://mirrors.aliyun.com/pypi/simple/
# https://pypi.mirrors.ustc.edu.cn/simple/
# 如果换源后警告,添加信任即可
python -m pip install <module_name> --trusted-host pypi.tuna.tsinghua.edu.cn


# pip更新
python -m pip install --upgrade pip
# 安装模块
python -m pip install <module_name>
# 也可以用源码安装,即包含setup.py的文件夹或者tar.gz压缩包
python -m pip install "/path/to/project_folder"
# 更新模块
python -m pip install --upgrade <module_name>
# 更新所有模块
python -m pip install pip-review
python -m pip-review --local --interactive
# 列出已安装的模块
python -m pip list
# 卸载模块
python -m pip uninstall <module_name>


# 安装虚拟环境模块,默认python3是内置venv的,便携版python3或python2则需安装virtualenv模块,对应的创建环境命令也需更改
python -m pip install --upgrade virtualenv
# 创建虚拟环境,使得项目使用的模块可以单独存在,不影响全局的模块
# 默认虚拟环境中的模块都需要显式安装才可用,如果想在该虚拟环境中使用系统已安装的模块则需指定--system-site-packages
# 该命令会创建DIRECTORY目录,并生成pyvenv.cfg文件、Lib及Scripts文件夹(Linux下为bin文件夹),里面包含符号链接
python -m venv <path/to/DIRECTORY>
python -m virtualenv <path/to/DIRECTORY>
# Windows激活虚拟环境
.\DIRECTORY\Scripts\activate
# Linux激活虚拟环境
source ./DIRECTORY/bin/activate
# 取消激活虚拟环境
deactivate
# 要删除虚拟环境则删除整个目录即可
rm -rf DIRECTORY
# 导出项目所需模块列表
python -m pip freeze > requirements.txt

# 一键安装项目所需的模块,一般目录下会有一个requirements.txt文件
python -m pip install -r requirements.txt
# 检查模块是否已经安装
python -m pip check -r requirements.txt
# 一键卸载第三方模块,原理是先导出requirements.txt,再根据requirements.txt卸载,不过会把pip也卸载掉,需重新安装pip
python -m pip uninstall -r requirements.txt -y

在联网环境下下载whl文件,以便离线安装模块:

# 下载whl文件,platform一般是linux_x86_64、win_amd64、macosx_10_9_x86_64等
python -m pip download <package_name> --only-binary=:all: --wheel --platform <platform> --python-version <python_version>
# 比如
python -m pip download numpy --only-binary=:all: --wheel --platform win_amd64 --python-version 311

# 离线环境安装whl,需指定禁止查询在线索引(--no-index)以及在当前目录下查找whl文件进行安装(--find-links)
python -m pip install --no-index --find-links="/path/to/packages" <package_name.whl>


# 根据requestments.txt批量下载whl到文件夹,默认只会下载当前platform下的包,且如果安装环境下的pip版本过低可能会报错
python -m pip download -r requestments.txt -d ./pip_packages
# 离线安装requestments.txt中的包
python -m pip install --no-index --find-links=./pip_packages -r requirements.txt 

PHP

LAMP

sudo add-apt-repository ppa:ondrej/php
sudo apt-get update
sudo apt-get install apache2
systemctl status apache2    # 检查apache2是否启动
/etc/init.d/apache2 start
/etc/init.d/apache2 stop
/etc/init.d/apache2 restart


sudo apt-get install mysql-server mysql-client libmysqlclient-dev
sudo netstat -tap | grep mysql  # 检查mysql是否安装成功
sudo gedit /etc/mysql/debian.cnf    # 查看mysql默认用户名密码
mysql -u debian-sys-maint -p    # 登录mysql
update mysql.user set authentication_string=password('password') where user='debian-sys-maint'and Host = 'localhost';   # 更改密码
update mysql.user set user="user" where user="debian-sys-maint";    # 更改用户名
flush privileges;   # 刷新权限


sudo apt-get install mariadb-server-10.0 mariadb-client-10.0
sudo mysql_secure_installation  # 配置Mariadb

sudo apt-get install php7.2
sudo apt-get install php7.2-mysql libapache2-mod-php7.2 php7.2-curl php7.2-json php7.2-cgi

sudo service mysql restart
sudo service apache2 restart

Ruby

sudo apt-get install curl ruby

系统配置

禁用guest

sudo gedit /usr/share/lightdm/lightdm.conf.d/50-no-guest.conf
# (粘贴)
[SeatDefaults]
allow-guest=false

关闭错误报告

sudo rm /var/crash/*
sudo gedit /etc/default/apport

调节亮度

sudo gedit /sys/class/backlight/intel_backlight/brightness

CA证书安装位置:/usr/local/share/ca-certificates/

其他软件

使用flatpak应用框架: https://flatpak.org/setup/Ubuntu、https://flathub.org

firefox: https://support.mozilla.org/en-US/kb/install-firefox-linux

Chrome: https://www.google.cn/intl/en_uk/chrome/

sougou输入法: http://pinyin.sogou.com/linux/

# 装完再安装依赖
sudo apt install -f
# 若无法显示界面,尝试安装以下依赖
sudo apt install libqt5qml5 libqt5quick5 libqt5quickwidgets5 qml-module-qtquick2
sudo apt install libgsettings-qt1
# 若还是不能运行,尝试卸载ibus
sudo apt purge ibus

WPS

sudo apt-get install wps-office

解决字体缺失、在Ubuntu22.04上无法打开等问题

# 解决字体缺失
# 先下载字体文件wps-symbol-fonts.zip,解压到/usr/share/fonts/wps-office/或/home/xxx/.local/share/fonts/wps-office
sudo mkfontscale
sudo mkfontdir
sudo fc-cache

# 解决在Ubuntu22.04上无法打开
# 给WPS的安装目录设置777的权限
sudo chmod 0777 -R  /opt/kingsoft/wps-office
# 删除之前WPS的安装设置
rm -rf  ~/.config/Kingsoft/

VLC: http://www.videolan.org

sudo snap install vlc

Haroopad: http://pad.haroopress.com/user.html

VSCode: https://code.visualstudio.com/

GIMP

sudo apt-get install gimp

shutter

sudo add-apt-repository ppa:shutter/ppa
sudo apt-get update && sudo apt-get install shutter

octave

sudo apt-get install octave

BleachBit: http://www.bleachbit.org/download/linux

VirtualBox: https://www.virtualbox.org

sudo apt install virtualbox virtualbox-ext-pack virtualbox-guest-additions-iso

Veracrypt: https://www.veracrypt.fr/en/Downloads.html

# 若不能运行,尝试安装libfuse2
sudo apt install libfuse2

AndroidStudio: https://developer.android.google.cn/studio

Genymotion: https://www.genymotion.com

jMonkeyEngine: https://github.com/jMonkeyEngine/jmonkeyengine

Wudao-dict: https://github.com/ChestnutHeng/Wudao-dict

indicator-sysmonitor: https://github.com/fossfreedom/indicator-sysmonitor

Katoolin: https://github.com/LionSec/katoolin

FileZilla: https://filezilla-project.org

Wine: https://wiki.winehq.org/Ubuntu

Pandoc: http://pandoc.org/installing.html#linux

FFmpeg: https://ffmpeg.org/download.html

Mathematica: http://www.wolfram.com/mathematica/

Netease Cloud Music: http://music.163.com/#/download

常用命令

命令行环境变量设置

# 查看当前环境变量
printenv
# 或者
env

# 临时设置环境变量
export VARIABLE_NAME="value"
# 临时追加环境变量,以PATH为例
export PATH="$PATH:/new/directory/path"

# 为当前用户永久设置环境变量,一般会根据不同系统把环境变量放在.bashrc、.profile或.bash_profile文件中
echo 'export VARIABLE_NAME="value"' >> ~/.bashrc
source ~/.bashrc

# 同理,对所有用户,环境变量一般放在/etc/profile或/etc/environment文件中
sudo echo 'export VARIABLE_NAME="value"' >> /etc/profile

解决ubuntu与windows的时差

timedatectl set-local-rtc 1 --adjust-system-clock
sudo hwclock --localtime --systohc

用户组管理,以安装Android Studio硬件加速(KVM)为例

# 检测是否支持kvm
kvm-ok
# 安装kvm
sudo apt-get install qemu-kvm libvirt-bin ubuntu-vm-builder bridge-utils
# 将当前用户添加到KVM组和libvirtd组
sudo adduser myusername kvm
sudo adduser myusername libvirt-qemu

# 卸载
# 查看用户/用户组
sudo cat /etc/shadow
sudo cat /etc/group
# 如果要把用户从用户组中移除
sudo gpasswd -d myusername kvm
sudo gpasswd -d myusername libvirt-qemu
# 删除用户组
sudo groupdel kvm
sudo groupdel libvirt-qemu

修复Ubuntu无法访问Windows磁盘分区

sudo apt-get install ntfs-3g

让gedit显示GB2312

sudo apt-get install dconf-tools
dconf-editor

# 依次点开->org->gnome->gedit->preferences->encodings,把Custom value改成
# ['UTF-8', 'GB18030', 'GB2312', 'GBK', 'BIG5', 'CURRENT', 'UTF-16']

解压/压缩命令

7z x file file
tar -jxvf file.tar.bz2
tar -zxvf file.tar

7za a -t7z -r test.7z ~/tozip/*
tar zcvf test.tar.gz ~/tozip/*
tar jcvf test.tar.bz2 ~/tozip/*

unzip -O cp936 test.zip # 解决乱码问题

清理内核

uname -a
sudo dpkg --get-selections |grep linux
sudo apt-get purge linux-headers-x.x.x-xx linux-image-x.x.x-xx-generic

sudo update-grub

修复引导

sudo -i
add-apt-repository ppa:yannubuntu/boot-repair
apt-get update
apt-get install -y boot-repair
boot-repair

grep查找字符串

# 在当前目录下的所有文件的内容中查找字符串str(其中 -r 是递归查找, -n 是显示行号)
grep -rn "str" ./

# 查找文件名包含指定字符串
find . -name 'str'

# 也可以结合起来用
find ./ -name "*.*" | xargs grep "Hello"

# 或者(其中 -l 表示只显示文件名)
find . | xargs grep -ri "Hello" -l

# 如果不知道文件所在的大致目录,只知道文件的类型(比如.txt),可以在根目录(/)下查找
find / -type f -name "*.txt" | xargs grep "Hello"

查看、清理进程

ps -aux | grep XXX
kill -9 PID

网卡开启monitor模式

iwconfig
iwconfig wlan0 mode monitor
airodump-ng wlan0

iwconfig
airmon-ng start wlan0
iwconfig
airodump-ng mon0
airodump-ng -d BSSID_address --channel 11 -w outputfile mon0
airmon-ng stop wlan0

其他命令

Windows常用命令

安装win10以上的系统时,强制要求联网并登录账号,在联网界面,可以按Shift+F10调出命令行,然后执行oobe\bypassnro,重启后会出现没有网络的选项。

Windows Defender保护历史记录路径在C:\ProgramData\Microsoft\Windows Defender\Scans\History\Service\DetectionHistory,删除该文件夹下的所有文件即可删除记录。

diskpart命令:想要知道分卷的编号,先用cmd执行diskpart进入新的命令行窗口,然后执行:

# 列出所选磁盘的分卷
list disk
select disk n # n为要选择的磁盘编号
list partition

# 或者显示所有分卷,但是有的隐藏分卷不会被列出来(随便选择一个磁盘后才能使用)
list volume

# 还可以给分卷分配盘符
select partition n # n为要选择的分卷编号
assign letter=D

bcdedit命令

# 列出所有的BCD启动项
bcdedit /enum # 或者不指定参数,直接使用bcdedit也可以列出
# 设置默认引导项
bcdedit /default {identifier}
# 设置超时时间(单位为秒)
bcdedit /timeout 10
# 创建引导项,一般会在创建时用“/d”指定描述
bcdedit /create /d "new_system"
# 更改引导项的参数,比如描述(即菜单上显示的名字)、磁盘分卷等
bcdedit /set {identifier} description "new description"
bcdedit /set {identifier} osdevice partition=\Device\HarddiskVolume2
# 用Grub引导Windows,其中"{bootmgr}"是Boot Manager的标识符
#({bootmgr}中Windows默认的引导路径是 \EFI\Microsoft\Boot\bootmgfw.efi,Ubuntu默认的引导路径是 \EFI\ubuntu\grubx64.efi)
#(BCD菜单中默认Windows的引导路径是\Windows\system32\winload.efi)
bcdedit /set {bootmgr} path \EFI\ubuntu\grubx64.efi
bcdedit /set {identifier} path \Windows\system32\winload.efi
# 更简单的创建方法是复制现有的配置再更改,其中“{current}”是指当前系统的引导项
bcdedit /copy {current} /d "new_system"
# 用“/create”创建的引导项不会出现在BCD菜单中,需通过“/displayorder”指定顺序才会显示
bcdedit /displayorder {identifier1} {identifier2} ...
# 在最后面添加引导项
bcdedit /displayorder {identifier} /addlast
# 删除引导项
bcdedit /delete {identifier}
# 备份BCD
bcdedit /export c:\bcdbak
# 恢复BCD
bcdedit /import c:\bcdbak
# 禁用驱动签名,有时候驱动有问题无法开机可以试试
bcdedit /set nointegritychecks on

注意:bcdedit无法识别不同硬盘,只能识别不同分卷,要引导另一个硬盘上的分卷,就根据disk0、disk1等,按顺序执行diskpartlist partition命令,然后顺延volume编号,得到\Device\HarddiskVolume的号码,再设置osdevice partition=xxx;比如disk0有两个volume,disk1中第一个volume是另一个系统,那么就是\Device\HarddiskVolume3,依此类推。

bcdboot命令

C:
cd C:\Windows\System32
bcdboot C:\Windows /addlast /s D:

命令参数解析:

修改cmd默认编码为UTF-8

# 查看当前默认编码,936为GBK,65001为UTF-8
chcp
# 临时修改为UTF-8
chcp 65001

# 永久修改则需改注册表,注册表找到如下路径
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Command Processor
# 然后选中Command Processor,右键新建字符串,命名为autorun,值填入chcp 65001>nul

命令行设置环境变量

# 查看所有环境变量
set
# 查看比如以pa开头的环境变量
set pa

# 临时修改或追加环境变量,值为""表示清空该环境变量
set "VARIABLE_NAME"="value"
set "path"="%path%;xxx;"

# 永久修改或追加环境变量,不加/m修改的是当前用户环境变量,加/m表示修改系统环境变量
setx "VARIABLE_NAME" "value"
setx "VARIABLE_NAME" "%VARIABLE_NAME%;value;"
setx "VARIABLE_NAME" "value" /m
setx "VARIABLE_NAME" "%VARIABLE_NAME%;value;" /m

清除powershell记录

Remove-Item (Get-PSReadlineOption).HistorySavePath

管理员权限相关

# 检查当前是否以管理员权限运行,核心思想就是试图访问需要管理员身份才可以访问的资源,无权访问结果为0
REG QUERY "HKU\S-1-5-19"

# 申请管理员权限
# VBS方式
%1 mshta vbscript:CreateObject("Shell.Application").ShellExecute("cmd.exe","/c %~s0 ::","","runas",1)(window.close)&&exit
cd /d "%~dp0"
# powershell方式,其中%~sdpnx0指当前批处理文件
powershell -Command "Start-Process '%~sdpnx0' -Verb RunAs"&&exit

# 结合使用
REG QUERY "HKU\S-1-5-19">NUL 2>&1 || (powershell -Command "Start-Process '%~sdpnx0' -Verb RunAs"&&EXIT)


# 将当前目录下的run.exe注册为需要使用管理员运行的程序,这样以后打开run.exe都会弹UAC框
reg add "HKCU\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers" /f /v "%~dp0\run.exe" /d "~ RUNASADMIN" >NUL 2>NUL


# 让需要管理员权限的软件以普通权限运行,原理是通过设置环境变量来使用兼容层运行
cmd /min /C "set __COMPAT_LAYER=RUNASINVOKER && start "" "C:\my programs\file.exe ""
# 或者使用时把软件拖到cmd文件的图标上
cmd /min /C "set __COMPAT_LAYER=RUNASINVOKER && start "" %1" ""

其他常用命令

# 遍历目录,并执行命令,比如递归遍历当前目录下所有jpg并复制到指定文件夹
forfiles /p . /m *.jpg /s /c "cmd /c copy @path D:\photos"
# 获取帮助
forfiles /?

# 在指定的文件中查找字符串
findstr "str" test.txt
# 在当前目录下的所有文件里查找字符串(其中/s表示包含子目录,/n表示显示行号,/i表示忽略大小写)
findstr /s /n /i "str" *.*

# 比较两个文件
fc file1.txt file2.txt
# 获取帮助
fc /?

# windows下创建任意大小空白文件,比如1G,即1024*1024*1024*1
fsutil file createnew 1.txt 1073741824

# 合并文件(比如ts)
copy /b  .\*.ts  .\new.ts

# 得到文件的MD5
certutil -hashfile  filename MD5

# 证书管理器
certmgr.msc

# MSConfig
msconfig

# 将文件夹映射成虚拟磁盘
subst A: C:\Downloads
# 不带参数即查看映射
subst
# 删除映射
subst A: /D

# Bitlocker回锁
manage-bde -lock D:

# 查看当前的文件类型关联(cmd输入,不指定类型则查看所有)
assoc .mp4
# 指定打开方式(等号后面为空就是删除关联的打开程序的意思)
assoc .mp4=WMP11.AssocFile.MP4
# 文件类型关联的软件对应注册表项(在两处同时删除就和使用命令行删除关联一样的效果):
# HKEY_CLASSES_ROOT
# HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\

重定向部分系统目录到当前文件夹:

@echo off
setlocal

# 设置"批处理文件名_Data"为存放数据的文件夹
set "rootfolder=%~dp0\%~n0_Data"
# 修改常用系统文件夹路径,核心思想是修改目录变量
set "ProgramData=%rootfolder%\ProgramData"
set "UserProfile=%rootfolder%\UserProfile"
set "LocalAppData=%UserProfile%\AppData\Local"
set "AppData=%UserProfile%\AppData\Roaming"

if not exist "%rootfolder%" mkdir "%rootfolder%"
if not exist "%ProgramData%" mkdir "%ProgramData%"
if not exist "%UserProfile%" mkdir "%UserProfile%"
if not exist "%UserProfile%\AppData" mkdir "%UserProfile%\AppData"
if not exist "%LocalAppData%" mkdir "%LocalAppData%"
if not exist "%AppData%" mkdir "%AppData%"

# 把批处理命名为目标exe同名,并放在同一个目录下,双击批处理即可运行exe
start "" "%~n0.exe"

endlocal

win11右键菜单更改:

# win11右键菜单更改
# Win10模式
reg.exe add "HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32" /f /ve
taskkill /f /im explorer.exe
start explorer.exe
# win11模式
reg.exe delete "HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}" /f
taskkill /f /im explorer.exe
start explorer.exe

清理任务栏图标记录:

# 关闭Windows外壳程序explorer
taskkill /f /im explorer.exe
# 清理系统图标缓存数据库
attrib -h -s -r "%userprofile%\AppData\Local\IconCache.db"
del /f "%userprofile%\AppData\Local\IconCache.db"
attrib /s /d -h -s -r "%userprofile%\AppData\Local\Microsoft\Windows\Explorer\*"
del /f "%userprofile%\AppData\Local\Microsoft\Windows\Explorer\thumbcache_32.db"
del /f "%userprofile%\AppData\Local\Microsoft\Windows\Explorer\thumbcache_96.db"
del /f "%userprofile%\AppData\Local\Microsoft\Windows\Explorer\thumbcache_102.db"
del /f "%userprofile%\AppData\Local\Microsoft\Windows\Explorer\thumbcache_256.db"
del /f "%userprofile%\AppData\Local\Microsoft\Windows\Explorer\thumbcache_1024.db"
del /f "%userprofile%\AppData\Local\Microsoft\Windows\Explorer\thumbcache_idx.db"
del /f "%userprofile%\AppData\Local\Microsoft\Windows\Explorer\thumbcache_sr.db"
# 清理 系统托盘记忆的图标
echo y|reg delete "HKEY_CLASSES_ROOT\Local Settings\Software\Microsoft\Windows\CurrentVersion\TrayNotify" /v IconStreams
echo y|reg delete "HKEY_CLASSES_ROOT\Local Settings\Software\Microsoft\Windows\CurrentVersion\TrayNotify" /v PastIconsStream
# 重启Windows外壳程序explorer
start explorer

注册表相关

打开注册表regedit

设置中,“安装的应用”项目存放位置(根据DisplayName判断):

此电脑中各种虚拟盘符对应注册表项:

手动添加文件右键菜单:

进入          HKEY_CLASSES_ROOT\*\shell\
在下面新建一项     Editplus
在新建的项目中,再新建一个项      command
之后在【HKEY_CLASSES_ROOT\*\shell\Editplus\command\】的默认值中,写入Editplus的绝对路径,并在后面添加  %1 。比如:C:\Program Files\EditPlus\editplus.exe %1
如果要指定图标,可以在【HKEY_CLASSES_ROOT\*\shell\Editplus】中添加字符串值,名字填 icon ,值填ico图标路径或者exe文件路径
如果需要多级菜单,在【HKEY_CLASSES_ROOT\*\shell\Editplus】中添加字符串值 SubCommands ,值不用填写,然后在下面新建一项 shell ,再在下面填新建你要显示在二级菜单中的项,并添加command项指定要运行的程序。多级菜单以此类推。
路径参数:
%1  文件路径
%2  系统默认的打印机
%3  文件扇区
%4  端口
%D  文件路径
%L  文件长路径
%V  文件路径
%W  当前文件的父目录的路径

关闭ms-gamingoverlay弹框:

暂停Windows更新至2099年(新建reg格式文件粘贴再运行):

Windows Registry Editor Version 5.00
 
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings]
"FlightSettingsMaxPauseDays"=dword:00000e42
"PauseFeatureUpdatesStartTime"="2020-01-01T00:00:01Z"
"PauseFeatureUpdatesEndTime"="2099-01-01T00:00:02Z"
"PauseQualityUpdatesStartTime"="2020-01-01T00:00:01Z"
"PauseQualityUpdatesEndTime"="2099-01-01T00:00:02Z"
"PauseUpdatesStartTime"="2020-01-01T00:00:01Z"
"PauseUpdatesExpiryTime"="2099-01-01T00:00:02Z"

Veracrypt常用命令

# 加载加密卷
veracrypt /beep /volume \Device\Harddisk0\Partition2 /password "123" /keyfile "1.txt" /auto /letter D /explore /quit
# 卸载加密卷
veracrypt /beep /dismount D /quit

命令参数解析:

VirtualBox常用命令

VBoxManage默认在C:\Program Files\Oracle\VirtualBox\VBoxManage.exe,退出独占键盘和鼠标的默认快捷键是右边的Ctrl+Alt

# 压缩虚拟机
VBoxManage modifyhd D:\centos.vdi --compact

# 查看所有的虚拟磁盘
VBoxManage list hdds
# 删除虚拟磁盘(虚拟硬盘的文件也会被删除)
VBoxManage closemedium disk "<虚拟硬盘完整路径>" --delete

使用VirtualBox从本地硬盘启动系统,参考Using a Raw Host Hard Disk From a Guest

1、确定硬盘DeviceID,或硬盘名称:

# Windows下查看硬盘DeviceID
wmic diskdrive list brief /format:list

# Linux下查看硬盘信息有很多种方法,以下任选一种即可
sudo fdisk -l
sudo df -h
sudo lshw -class disk
sudo cat /proc/partitions
sudo parted -l

2、创建vmdk,指向实体硬盘:

# Windows下的命令
# 使用管理员进入cmd执行,而且以后如果要使用该创建的vmdk要用管理员运行Virtalbox
VBoxManage internalcommands createrawvmdk -filename "D:\physicDrive.vmdk"  -rawdisk \\.\PHYSICALDRIVE0
# 还可以指定使用哪几个分卷(ESP和MSR等EFI分区记得选上,不然没法启动系统)
VBoxManage internalcommands createrawvmdk -filename "D:\physicDrive.vmdk"  -rawdisk \\.\PHYSICALDRIVE0 -partitions 1,2,3

# Linux下要先设置读写权限,而且以后每次使用该创建的vmdk都要设置读写权限
sudo chmod 666 /dev/nvme0*
sudo chmod 666 /dev/sda*
# 可以给同一个虚拟机创建多个不同的虚拟硬盘
VBoxManage internalcommands createrawvmdk -filename "physicDrive_nvme0n1.vmdk" -rawdisk /dev/nvme0n1 -relative
VBoxManage internalcommands createrawvmdk -filename "physicDrive_sda.vmdk" -rawdisk /dev/sda -partitions 1,2,3 -relative

3、打开Virtualbox,创建虚拟机:

git常用命令

# 安装并配置用户名、邮箱
sudo apt-get install git
git config --global user.name "Your Name"
git config --global user.email "email@example.com"

# github通过SSH令牌进行身份验证
# 生成公钥
ssh-keygen -t rsa -C "你注册github时的邮箱"
# 查看公钥
gedit ~/.ssh/id_rsa.pub
# 上传公钥到github:打开github网站settings->SSH and GPGkeys->new SSH key->粘贴公钥
# 测试密钥是否添加成功:
ssh -T git@github.com

# 查看远程仓库
git remote -v
# 取消链接远程仓库,仓库别名通常是origin
git remote rm [远程仓库别名]
# 把当前文件夹链接到远程仓库,仓库别名通常是origin
git remote add [远程仓库别名] [ssh-url]

# 初始化本地仓库
git init
git remote add origin git@github.com:[username]/[repo name].git
# 上传到github
git add --all
git commit -m "update"
git push -u origin master

# 不删除项目情况下删除所有commit记录
# 原理是新建分支->文件移至新分支->提交更改(本地)->删除原分支->把新分支改名为master->提交至github)(需要重新上传所有文件):
git checkout --orphan latest_branch
git add -A
git commit -am "update"
git branch -D master
git branch -m master
git push -f origin master

FFmpeg常用命令

官网:FFmpeg

# 列出所有支持的格式(也就是-f后面可以接的参数)
ffmpeg -formats
# 查看支持的编码器(也就是-vcodec后面可以接的参数)
ffmpeg -codecs
# 查看支持的滤镜(也就是-vf后面可以接的参数):
ffmpeg -filters
# 显示所有可用的硬件加速器(即GPU加速,需下载显卡相关的驱动并使用显卡相关的解码器及编码器)
ffmpeg.exe -hwaccels

# 获取视频信息
ffmpeg -i video.mp4

# 视频格式转换并重新编码(没有指定任何编码器或copy则默认重新编码),-f指定转码的格式,比如flv转成mp4,如果不指定则自动检测输出文件的后缀;-y表示若输出文件存在,则自动覆盖输出文件,而-n则表示不要覆盖输出文件
ffmpeg -i input.flv -f mp4 -y output.mp4
# -acodec copy:音频流执行copy,视频流重新解码、编码;注意,所有的编码指令都应在输出参数前面指定
ffmpeg -i input.mp4 -acodec copy -f mp4 output.mp4
# -vcodec copy:视频流执行copy,音频流重新解码、编码
ffmpeg -i input.mp4 -vcodec copy -f mp4 output.mp4
# -codec copy:音频流和视频流都执行copy,不重新解码、编码
ffmpeg -i input.mp4 -codec copy -f mp4 output.mp4

合并视频方法一,在视频所在文件夹中新建一个txt文件,把要合并的视频文件按顺序写上,比如filelist.txt:

file '1.mp4'
file '2.mp4'
file '3.mp4'

(以上文件内容可以用dir /b /s /a-d > filelist.txt命令生成文件列表再修改,其中/s表示递归遍历,/a-d表示只列出文件)

然后执行:

# 方法一:合并mp4,使用concat demuxer方法,该方法要求视频音频的属性完全一样,且不会再进行解码、编码,速度较快
ffmpeg -f concat -i filelist.txt -c copy output.mp4
# 方法二:合并mp4,使用concat filter方法,该方法要求视频之间的分辨率和帧率一致,支持合并的同时重新解码、编码视频
ffmpeg -i 1.mp4 -i 2.mp4 -i 3.mp4 -i 4.mp4 -filter_complex concat=n=4:v=1:a=1 -f mp4 output.mp4
# 方法三:ts格式可以使用concat protocol方法,直接在参数里指定concat的文件名,类似Linux中的cat命令
ffmpeg -i "concat:1.ts|2.ts|3.ts" -codec copy output.ts

# 先合并ts,然后将合并后的ts重新编码、转码为mp4
ffmpeg -f concat -i filelist.txt -acodec copy -vcodec copy -absf aac_adtstoasc output.mp4

# mp4转为ts需要指定过滤器,-vbsf指定视频过滤器
ffmpeg -i input.mp4 -vcodec copy -acodec copy -vbsf h264_mp4toannexb output.ts

# 其他的一些常用编码器
# mp4转为webm
ffmpeg -i input.mp4 -c:v libvpx -c:a aac output.webm
# mp4转flv,-g可以设置关键帧间隔,比如45帧
ffmpeg -i input.mp4 -c:v libx264 -c:a aac -g 45 output.flv

# 结合cmd的循环命令,可以批量重新解码、编码
for %%a in ("*.mp4") do ffmpeg -i "%%a" -c:v libx264 -c:a aac -y "%%a".mp4

其他常用命令:

# 视频压缩,-crf设置视频质量,取值范围为0~51,数值越大,画质越差,生成的文件就越小,一般取18即可让输出视频质量和输入视频相当;-r设置视频的帧率;-preset指定的编码速度越慢,获得的压缩效率就越高,取值有veryslow、slower、slow、medium、fast、faster、veryfast、superfast、ultrafast 
ffmpeg -i input.mp4 -threads 2 -vcodec libx264 -acodec copy -preset veryslow -r 60 -crf 18 output.mp4

# 获取视频分辨率
ffprobe -v error -select_streams v:0 -show_entries stream=width,height -of csv=s=x:p=0 input.mp4
# 调整视频分辨率,比如调整为w:1920 h:1080;如果需要保持纵横比,那么就指定宽和高的其中一个,另一个设置为-1,比如-1:720
ffmpeg -i input.mp4 -vf scale=1920:1080 -preset veryslow -crf 18 output.mp4
# 调整视频分辨率时,支持使用变量计算宽高,比如宽和高都减少一半
ffmpeg -i input.mp4 -vf "scale=iw/2:ih/2" -preset veryslow -crf 18 output.mp4  

# 视频切割
# 读取input.mp4文件,并将其转换为HLS格式,并生成HLS播放列表文件output.m3u8和对应的媒体切片文件output_001.ts、output_002.ts等等
# 其中-hls_time指定HLS切片时长,单位为秒;-hls_list_size指定HLS播放列表中切片数量,为0则表示生成无限大小的播放列表;-hls_segment_filename指定HLS切片文件名
ffmpeg -i input.mp4 -c:v libx264 -c:a aac -hls_time 10 -hls_list_size 0 -hls_segment_filename "output_%03d.ts" output.m3u8
# 另一种切割方法
ffmpeg -i input.mp4 -c:v libx264 -c:a aac -segment_time 10 -segment_format mpegts -segment_list output.m3u8 output_%03d.ts

# 音视频分离
# -an:audio no,只保留视频,去除音频
ffmpeg -i input.mp4 -vcodec copy -an output.mp4
# -vn:video no,只保留音频,去除视频
ffmpeg -i input.mp4 -acodec copy -vn output.mp4
# 只保留音频,去除视频,且导出为MP3格式
ffmpeg -i input.mp4 -vn -acodec libmp3lame -ab 320k -ar 44100 -f mp3 output.mp3

# 截取视频,-ss指定开始时间、-t指定持续时间,或用-to指定结束时间,单位为秒,-s指定分辨率,但是直接截取可能会导致截取时间点不准确以及开头黑屏
ffmpeg -i input.mp4 -ss 00:01:10.0 -t 00:00:05 -s 1280x720 -codec copy -f flv output.flv
# 为了避免以上问题,可进行重新编码
ffmpeg -i input.mp4 -ss 00:00:01.123 -t 00:00:05 -c:v libx264 -c:a aac output.mp4
# 如果对准确度要求不高,可按关键帧截取视频,这样更快,注意,-accurate_seek必须放在-i参数之前
ffmpeg -ss 10 -t 5 -accurate_seek -i input.mp4 -codec copy output.mp4

# 顺时针旋转90°
ffmpeg -i input.mp4 -vf "transpose=1" output.mp4
# 逆时针旋转90°
ffmpeg -i input.mp4 -vf "transpose=2" output.mp4
# 水平翻转
ffmpeg -i input.mp4 -vf hflip output.mp4
# 垂直翻转
ffmpeg -i input.mp4 -vf vflip output.mp4

# 视频倒放、音频不变
ffmpeg -i input.mp4 -vf reverse reversed_video.mp4
# 音频倒放,视频不变
ffmpeg.exe -i input.mp4 -map 0 -c:v copy -af "areverse" reversed_audio.mp4
# 音视频都倒放
ffmpeg -i input.mp4 -vf reverse -af areverse -preset superfast reversed.mp4 
# 两倍速播放,setpts=PTS/2指视频变为2倍速,atempo=2指音频变为2倍速,对音视频进行加速时,如果不想丢帧,可以用-r参数指定输出视频FPS,用-ar参数指定音频采样率(Hz)
ffmpeg -i input.mp4 -r 60 -vf setpts=PTS/2 -af atempo=2 output.mp4
# 音量调整为80%
ffmpeg -i input.mp4 -af "volume=0.8" output.mp4

# hstack:左右拼接视频;vstack:上下拼接视频
ffmpeg -i input1.mp4 -i input2.mp4 -lavfi hstack output.mp4
# 3个视频左右拼接
ffmpeg -i input1.mp4 -i input2.mp4 -i input3.mp4 -lavfi hstack=inputs=3 output.mp4

# 字幕格式转换
ffmpeg -i subtitle.srt subtitle.ass
# 添加硬字幕(srt或ass格式字幕)
ffmpeg -i input.mp4 -vf subtitles=subtitle.srt output_srt.mp4
ffmpeg -i input.mp4 -vf ass=subtitle.ass output_ass.mp4
# 添加软字幕(srt或ass格式同样操作)
ffmpeg -i input.mp4 -i subtitle.srt -c copy -c:s mov_text -metadata:s:s:0 language=chi ouptut_chi.mp4
# 添加多通道软字幕
ffmpeg -i input.mp4 -i ch.srt -i en.srt -map 0 -map 1 -map 2 -c copy -c:s mov_text -metadata:s:s:0 language=chi -metadata:s:s:1 language=eng output_chi_eng.mp4
# 提取软字幕(将第二个轨道subrip字幕轨道提取成srt文件,通过视频信息可查看第几个Stream是字幕)
ffmpeg -i input.mp4 -map "0:2" output.srt 

一些常见问题:

# 合并mp4时,若出现Unsafe file name错误,则添加参数"-safe 0"
ffmpeg -f concat -safe 0 -i filelist.txt -c copy output.mp4

# 解决时间轴的损坏
# 方法一:分离出视频、音频,再混合视频和音频,重新生成文件
ffmpeg -i input.mp4 -map 0:v -vcodec copy -bsf:v h264_mp4toannexb output_video.mp4
ffmpeg -i input.mp4 -vn output_audio.wav
ffmpeg -i output_video.mp4 -i output_audio.wav -c copy output_fixed.mp4
# 方法二:设定帧率为60fps(或其他想要的帧率),重新封装
ffmpeg -fflags +genpts -r 60 -i input.mp4 -vcodec copy output_fixed.mp4
# 方法三:如果两个视频的time_base(即tbn)不一样,合并之后时间轴出错可以用以下方法修复(按需取值)
ffmpeg -i input.mp4 -c:v copy -video_track_timescale 12800 output.mp4

pandoc常用命令

pandoc官网文档,安装完要添加到环境变量里;如果要生成PDF,还要安装(任选一个即可):TeX LiveMiKTeX

pandoc -s --toc --toc-depth=6 --katex="file:///path/to/katexfolder/" --css=cssfile.css -H jsfile.js --embed-resources --metadata title="title" infile.md -o outfile.html
pandoc -s --pdf-engine="path/to/xelatex.exe" -V mainfont="SimSun.ttc" --template="path/to/template.latex" -f markdown -t pdf infile.md -o outfile.pdf

命令参数解析:

注意:如果markdown中使用的图片等外部文件使用了相对路径,那么需要在markdown所在的目录下运行pandoc,否则找的是pandoc所在的目录,就会报错说找不到文件。

注意:用pandoc将markdown导出为html,数学公式会在annotation标签下保留latex源码,如果不想保留,可以通过以下命令删除(浏览器console执行,然后保存网页;部分浏览器保存后页内锚点会变成绝对路径,且文件开头会出现保存时间的注释,需修改):

(function(){
  //填入公式保存位置的选择器
  tagStrs=['annotation', 'span[class="katex-mathml"]', 'script[type="math\/tex"]'];
  tagStrs.forEach(
    function(tagStr){
      var tagElements = document.querySelectorAll(tagStr);
      for(let i = 0; i < tagElements.length; i++){
        tagElements[i].parentNode.removeChild(tagElements[i])
      }
    }
  );
})()

附一个仿Typora的css:

html {
  scroll-behavior: smooth;
}
body {
  /* 网页字体1rem,pdf字体10.5px,生成pdf时需修改字体大小*/
  font-size: 1rem;
  /* font-size: 10.5px; */
  line-height: 1.6;
  tab-size: 4;
  color: rgb(51, 51, 51);
  font-family: Microsoft YaHei,"Open Sans","Clear Sans", "Helvetica Neue", Helvetica, Arial, 'Segoe UI Emoji', sans-serif;
  -webkit-font-smoothing: antialiased;

  /* TOC的宽度是300px,根据TOC进行修改(生成pdf时需把这部分注释掉) */
  position: relative;
  top: 0;
  left: 300px;
  width: calc(90% - 300px);
  padding: 2em 5%;
}
h1,h2,h3,h4,h5,h6 {
  position: relative;
  margin-top: 1rem;
  margin-bottom: 1rem;
  padding-bottom: 0;
  font-weight: bold;
  line-height: 1.4;
  cursor: text;
}
h1 {
  font-size: 2.25em;
  line-height: 1.2;
  border-bottom: 1px solid #eee;
}
h2 {
  font-size: 1.75em;
  line-height: 1.225;
  border-bottom: 1px solid #eee;
}
h3 {
  font-size: 1.5em;
  line-height: 1.43;
}
h4 {font-size: 1.25em;}
h5 {font-size: 1em;}
h6 {font-size: 1em;color: #777;}
p,blockquote{ margin: 0.8em 0 !important; }
ul,ol,dl,table{margin: 0.8em 0;}
li>ol,li>ul {margin: 0 0;}
a {
  color: #4183C4;
  text-decoration: none;
}
hr {
  height: 2px;
  padding: 0;
  margin: 16px 0;
  background-color: #e7e7e7;
  border: 0 none;
  overflow: hidden;
  box-sizing: content-box;
}
li p.first {display: inline-block;}
ul,ol {padding-left: 20px;}
ul:first-child,ol:first-child {margin-top: 0;}
ul:last-child,ol:last-child {margin-bottom: 0;}
blockquote {
  border-left: 4px solid #dfe2e5 !important;
  padding: 0 15px;
  color: #777777 !important;
  background-color: #ffffff !important;
}
blockquote blockquote {padding-right: 0;}
table {
  padding: 0;
  word-break: initial;
  border-collapse: collapse;
}
table tr {
  border: 1px solid #dfe2e5;
  margin: 0;
  padding: 0;
}
table tr:nth-child(2n),thead {background-color: #f8f8f8;}
table th {
  font-weight: normal;
  text-align: unset;
  border-bottom: 0;
  border: 1px solid #dfe2e5;
  margin: 0;
  padding: 6px 13px;
}
table td {
  border: 1px solid #dfe2e5;
  margin: 0;
  padding: 6px 13px;
}
table th:first-child,table td:first-child {margin-top: 0;}
table th:last-child,table td:last-child {margin-bottom: 0;}
tt {
  border: 1px solid #e7eaed;
  background-color: #f8f8f8;
  border-radius: 3px;
  padding: 2px 4px 0px 4px;
  font-size: 0.9em;
}
code {
  border: 1px solid #e7eaed;
  background-color: #f3f4f4;
  border-radius: 3px;
  padding: 0 2px 0 2px;
  font-size: 0.9em;
}
img {
  width: 50%;
  height: 50%;
  display: block;
  vertical-align: middle;
  image-orientation: from-image;
  margin: auto;
}
figcaption {
  text-align: center;
}
@page {
  size: A4;
  /* 调整生成的PDF中上下左右空白的大小 */
  margin: 14mm 19.5mm;
}

/* 代码块显示行号,要求代码块的每行最外面有且只有一个span,否则行号会计算出错,目前pandoc测试没问题 */
pre>code{
  counter-reset: linenumber;
  display: block;
  white-space: pre;
  overflow: auto !important;
  padding: 0.2em;
  border-radius: 7px;
}
pre>code>span {
  counter-increment: linenumber;
  display: inline-block;
  line-height: 1.25em !important;
}
pre>code>span::before {
  content: counter(linenumber);
  display: inline-block;
  font-size: 0.9em;
  color: #999;
  min-width: 1.8em;
  margin-right: 0.5em;
  padding-right: 0.25em;
  text-align: right;
  border-right: 1px solid #999;
  line-height: 1.9em;
  user-select: none;
  pointer-events: none;
}

/* pandoc生成的TOC标签的id叫TOC,如果其他软件生成的id或class不一样就需要更改 */
#TOC {
  font-size: 0.8rem;
  position: fixed;
  top: 0;
  left: 0;
  width: 300px;
  height: 100%;
  padding: 32px 16px 48px 16px !important;
  box-shadow: 0 0 4px rgba(150,150,150,0.33);
  box-sizing: border-box;
  overflow: auto;
  scrollbar-color: #f5f5f5;
  scrollbar-width: 1px;
}
#TOC::-webkit-scrollbar{
  width: 1px;
  border-right:  1px solid #f5f5f5;
}
#TOC a{
  color: #333333;
  text-decoration: none;
}
#TOC a:hover{
  color: #333333 !important;
  text-decoration: underline !important;
}
#TOC ul { list-style: none; }
#TOC li { margin-bottom: 0.25rem; }
/* 屏幕太小则隐藏TOC */
@media (max-width: 700px) {
  #TOC { display: none; }
  body { left: 0px; width: 90%; }
}

附一个实现导航栏高亮当前项的javascript,通过-H jsfile.js参数导入:

<script type="text/javascript">
window.onload = function(){
  /* 点击页内锚点平滑滚动,且不更新地址栏 */
  document.querySelectorAll('a[href^="#"]').forEach(function(item,index,arr){
      item.addEventListener('click', function(e) {
          e.preventDefault();
          //获取导航项对应的ID锚点的元素,通过ID获取就不会将比如点“.”当作类选择器,可以处理符号冲突
          const target =  document.getElementById(decodeURI((item.href.substring(item.href.indexOf('#')+1))));
          if(target == null) { return; }
          target.scrollIntoView({ behavior: 'smooth' });
      });
  })

  /* 调用后,将TOC中当前导航项突出显示 */
  const toc_a = document.querySelectorAll('#TOC a');
  function updateTOC(){
    const scrollPosition = window.scrollY;//获取页面滚动的垂直位置
    let highlightTarget;
    for(let i=toc_a.length-1; i>=0; i--){//从后往前遍历,就可以找到最接近当前滚动位置上方的导航项
      const target = document.getElementById(decodeURI((toc_a[i].href.substring(toc_a[i].href.indexOf('#')+1))));//获取导航项对应的ID锚点的元素
      if(target == null) { continue; }
      const ItemPosition = target.offsetTop;//获取元素的垂直位置
      if (scrollPosition > ItemPosition && typeof(highlightTarget) == "undefined") {//判断元素位置是否在当前滚动位置的上方
        highlightTarget = toc_a[i];//记录要高亮的导航项
      } else if(typeof(highlightTarget) == "undefined" && i == 0) {//要是文章上方有的部分没有导航项与之对应,则将第一个导航项突出显示
        highlightTarget = toc_a[0];
      }
    }
    toc_a.forEach( item => {
      item.style.fontWeight = "";//移除所有的突出显示样式
    });
    if(typeof(highlightTarget) == "undefined") { return; }
    highlightTarget.style.fontWeight = "bold";//给当前的导航项添加突出显示样式
    if(!isInViewPort(highlightTarget)){//如果当前的导航项超出可视区域,那么就将导航项垂直居中
      highlightTarget.scrollIntoView({ block: "center"});
    }
  }
  //判断元素是否在可视区域内
  function isInViewPort(dom) {
    const viewHeight = window.innerHeight || document.documentElement.clientHeight;
    const viewWidth = window.innerWidth || document.documentElement.clientWidth;
    const { top, right, bottom, left } = dom.getBoundingClientRect();//当滚动条滚动时,top, left, bottom, right时刻会发生改变。
    //如果一个元素在视窗之内,那么它的top、left大于等于0,且bottom、right小于等于视窗宽度
    return (top >= 0 && left >= 0 && right <= viewWidth && bottom <= viewHeight);
  }
  //停止滚动200ms后才更新TOC
  let timer = null;
  window.addEventListener('scroll', () => {
    window.clearTimeout(timer);
    timer = window.setTimeout(() => { updateTOC() }, 200);
  });
};
</script>

如果想让超链接(页内锚点除外)在新标签页打开,可以在head中插入如下代码:

<base target="_blank">

Windows下使用pandoc批量转换markdown文件(使用前根据目录结构建好文件夹并放入文件):

echo off
chcp 65001
SET root_dir=%cd%
SET source=%root_dir%\_source
SET lib=%root_dir%\_lib
SET output=%root_dir%\output

mkdir %output%

for /R %source% %%i in (*.md) do (
  cd %%~dpi
  echo processing %%~ni%%~xi
  cmd /c pandoc -s --toc --toc-depth=6 --katex="file:///%lib:\=/%/katex/" --css="%lib%\blog.css" -H "%lib%\blog.js" --embed-resources --metadata title="%%~ni" %%i -o "%output%\%%~ni.html"
  cd %root_dir%
)

pause

Linux下使用pandoc批量转换markdown文件(使用前根据目录结构建好文件夹并放入文件):

root_dir=$(pwd)
source="${root_dir}/_source"
lib="${root_dir}/_lib"
output="${root_dir}/output"

mkdir "${output}"

function read_dir() {
  for file in `ls $1`; do
    if [ -d "${1}/${file}" ]; then
      # 如果是文件夹,则递归
      read_dir "${1}/${file}"
    else
      # 如果是文件,则执行命令
      if echo "${file}" | grep -q -E '\.md$'; then
        echo "processing ${file}"
        cd $1
        ${lib}/pandoc/bin/pandoc -s --toc --toc-depth=6 --katex="file:///${lib}/katex/" --css="${lib}/blog.css" -H "${lib}/blog.js" --embed-resources --metadata title="${file%%.*}" "${1}/${file}" -o "${output}/${file%%.*}.html"
        cd ${root_dir}
      fi
    fi
  done
}

read_dir ${source}

VSCode

1、安装Markdown All in One、Markdown Preview Enhanced插件,然后下载prince,并将prince的exe所在目录添加进Path环境变量;

2、打开VSCode,按Ctrl+Shift+P,输入Markdown Preview Enhanced: Customize Css,文件结构如下:

/* .markdown-preview.markdown-preview是正文部分的div的class */
.markdown-preview.markdown-preview {
  /* css... */
  &.prince {
    /* prince专属配置(可以覆盖外面写的css,可以把pdf和html不同的部分放进来,必须放在这里才能生效) */
    font-size: 10.5px;
  }
}
/* css... */

将前面pandoc的css稍作修改即可:

/* 去除TOC前面的三角形、正方形等list图标 */
.md-toc summary { list-style: none; }
.md-toc summary::-webkit-details-marker { display:none; }
.md-toc details div {
  display: block !important;
  list-style: none !important;
}
/* 去掉TOC中奇怪的空行 */
.md-toc ol {margin-bottom: 0;}
&.prince {
  /* pdf需更改字体大小,且不需要自己设置TOC,要删掉为TOC预留的位置 */
  font-size: 10.5px;
  position: static;
  top: 0;
  left: 0;
  width: 100%;
  padding: 0;

  @page {
    @bottom {
      /* PDF底部加页码(放在.markdown-preview.markdown-preview或&.prince等里面才会生效) */
      font-family: Microsoft YaHei;
      font-size: 0.5rem;
      content: counter(page) "/" counter(pages)
    }
  }
}

3、如果要生成带侧边栏TOC的html,进入VSCode的插件选项->进入Markdown Preview Enhanced插件的设置->找到Enable Script Execution并勾选,并在md文件的最前面加上如下代码(其中embed_local_images如果被设置为true,那么所有的本地图片将会以base64的形式嵌入到html中):

---
html:
  embed_local_images: true
  toc: true
  depth_from: 1
  depth_to: 6
  ordered: false
---

4、VSCode打开markdown文档->右键->MPE打开侧边预览,右边打开的窗口->右键->PDF(prince)->生成pdf文件;右键->HTML->HTML(offline)->生成html;

Typora

如果Typora想把markdown中使用的图片以base64的形式嵌入到导出的html中,需要下载compact_html,并在Typora设置->导出->html->勾选运行自定义命令->输入"D:\compact_html.exe" "${outputPath}"(改为你的compact_html.exe路径)

Hexo

Hexo基于Node.js,因此可以使用Node.js的gulp,来实现将图片以base64的形式嵌入到导出的html中,并将公式由mathjax转为svg,同时还可以精简html。

先安装所需模块:

# gulp要安装两次,一次全局,一次项目内
sudo npm install --global gulp-cli
npm install gulp --save-dev

npm install gulp-mathjax-page --save-dev
npm install gulp-html-minifier --save-dev

然后新建gulpfile.js如下(Hexo生成的html在./public下,如果是其他路径就自行更改):

var gulp = require('gulp');
var mathjax = require('gulp-mathjax-page');
var htmlmin = require('gulp-html-minifier');

function img2base64(){
    let through = require('through2');
    let path = require('path');
    let fs = require('fs');

    function transferImage(file, encoding, callback){
        if (file.isNull()) {
            return callback(null, file);
        }
        if (file.isStream()) {
            return callback(createError(file, 'Streaming not supported'));
        }
        let content = file.contents.toString();
        //比如音频,regx则是  /(<source[\s\S]*?src\s*=\s*[\"|\'])(.*?)([\"|\'][\s\S]*?>)/g
        let rule = /(<img[\s\S]*?src\s*=\s*[\"|\'])(.*?)([\"|\'][\s\S]*?>)/g;//注意,这样无法排除注释里的img标签,如果找不到对应的图片,会报错
        let imgList = content.match(rule) || [];
        if (imgList.length) {
            imgList.forEach(function(item) {
                let imageURL = item.replace(rule, '$2');
                if(imageURL.startsWith("data")){//防止已经base64转码的src再转码
                    return false;
                }
                if(/^http|https:/.test(imageURL)) {//排除网络图片
                    return false;
                }
                let route = path.join(__dirname, 'public', decodeURI(imageURL.replace(/\/prefix/,'')));//生成的图片地址和实际文件路径不一样,需要修正(自行更改)
                try{
                    let filepath = fs.realpathSync(route);
                    let imageContent = Buffer.from(fs.readFileSync(filepath)).toString('base64');
                    let extname = path.extname(imageURL).slice(1);
                    //比如音频,base64的开头则是  data:audio/mpeg;base64,
                    content = content.replace(item, item.replace(imageURL,'data:image/' + extname.toLowerCase() + ';base64,' + imageContent));
                }catch(err){
                    console.log(err);//文件不存在就输出错误然后跳过
                }
            });
        }
        file.contents = Buffer.from(content);
        this.push(file);
        callback(null, file);
    }
    return through.obj(transferImage);
}

gulp.task('mytask1', async() => {
    gulp.src('./public/**/*.html')
    .pipe(mathjax({ //latex公式生成svg
        mjpageConfig: {
            format: ['TeX'],
            singleDollars: true,
            cssInline: false,
            mhchem: {legacy: true}
        },
        mjnodeConfig: {
            svg: true,
            css: false,
            speakText: false
        }
    }))
    .pipe(img2base64())//图片转base64嵌入到html中
    .pipe(htmlmin({
        removeComments: true,//清除HTML注释
        collapseBooleanAttributes: false,//省略布尔属性的值 <input checked="true"/> ==> <input />
        removeEmptyAttributes: false,//删除所有空格作属性值 <input id="" /> ==> <input />
        collapseWhitespace: true,//压缩HTML
        minifyJS: true,//压缩页面JS
        minifyCSS: true//压缩页面CSS
    }))
    .pipe(gulp.dest('./public'))
})

最后执行gulp mytask1

关于使用Markdown的一些注意事项:

1、由于Windows和Linux路径分隔符不一样,插入的外部文件(如图片)不要带路径,最好和markdown文件放在同一目录,直接写文件名即可;

2、标题尽量不要出现Latex公式,否则生成的HTML或PDF的TOC点击后无法跳转(对于HTML可以F12改一下锚点id);

3、尽量不要对Latex公式加粗、斜体、高亮、下划线、删除线等,像VSCode和MarkText就不会解析这些**==等,而是直接显示到生成的HTML中;

4、行内公式要用两个$包裹,而不要用两个$$包裹;单独一行的公式(即用两个$$包裹的)不仅$$要换行,而且$$前后都要留有空行,否则MarkText不能正确解析;

5、如果公式要换行,要使用环境包裹,比如\begin{aligned}...\end{aligned}\begin{array}{cc}...\end{array}等,而且要用\\换行,而不要用\newline,否则pandoc的mathml无法识别;

6、虚线分割的矩阵,包括\begin{array}{cc:c}...\end{array}\hdashline,pandoc的mathml都无法识别;

7、微分符号要写做\mathrm{d},不要简写为\rm d,否则pandoc的mathml无法识别;

8、pandoc的mathml不支持verb|...|(其中两边的|可以换成任意除字母、空格、星号外的任意不与之间内容冲突的符号,只是习惯用|);

9、Latex中的中文最好用\text{...}包裹,否则pandoc的KaTex导出的html会报warning;

10、空集最好写\emptyset,而不要写做\empty,否则VSCode可能不识别(更新后好像已经支持了);

11、尽量不要出现两个连续的大括号,比如{{xxx}},否则会与hexo的语法冲突,报错Nunjucks Error;

12、尽量统一换行符,比如用Linux换行符\n,并统一使用UTF-8。

adb常用命令

SDK Platform Tools下载地址:官网国内专用

#启动adb服务
adb start-server
#关闭adb服务
adb kill-server
#查看连接adb的设备
adb devices
#使用基于pair的无线调试
adb pair <IP[:PORT]> [PAIRING CODE]
#连接网络设备
adb connect <IP[:PORT]>
#断开网络设备的链接
adb disconnect [IP[:PORT]]

#重启手机
adb reboot
#通过adb进入bootloader:
adb reboot bootloader
#通过adb进入recovery:
adb reboot recovery

#重新挂载文件系统
adb remount
#获取su权限
adb shell su

#获取当前(前台)用户的ID
adb shell am get-current-user
#获取所有现有用户的列表
adb shell pm list users
#查看支持最多用户数
adb shell pm get-max-users
#创建新用户并返回ID
adb shell pm create-user <userName>
#按ID移除特定用户
adb shell pm remove-user <userId>
#按ID启动用户
adb shell am start-user <userId>
#按ID将新用户切到前台来
adb shell am switch-user <userId>
#查看切换用户是否成功(u0即表示userId=0的用户应用正处于前台)
adb shell dumpsys activity a | adb shell grep 'Hist '

#所有应用列表:
adb shell pm list packages
#为特定用户列出软件包
adb shell pm list packages --user <userId>
#查找某个app
adb shell pm list packages "关键字"
#系统应用列表:
adb shell pm list packages -s
#已停用的系统应用列表:
adb shell pm list packages -s -d
#已启用的系统应用列表:
adb shell pm list packages -s -e
#查看某个应用的详细信息
adb shell dumpsys package <packageName>
#打开app(比如:adb shell am start -n com.topjohnwu.magisk/com.topjohnwu.magisk.ui.MainActivity)
adb shell am start -n 包名/包名.活动名
#打开指定用户下的app
adb shell am start --user <userId> 包名/包名.活动名
#以action的方式打开app(以打开输入法设置为例)
adb shell am start -a android.settings.INPUT_METHOD_SETTINGS
#以指定category的方式打开app(以打开通讯录为例)
adb shell am start -c android.intent.category.APP_CONTACTS
#结合起来用
adb shell am start -a android.intent.action.MAIN -c android.intent.category.LAUNCHER -n 包名/包名.活动名
#启动服务
adb shell am startservice 包名/.活动名
#恢复出厂设置
adb shell am broadcast -a android.intent.action.MASTER_CLEAR
#强行停止与该app关联的所有进程
adb shell am force-stop <packageName>
#终止所有后台进程
adb shell am kill-all

#安装app(可以使用-g参数在安装时直接授予所有所需权限、-r替换已存在应用(即保留数据并安装新包)、-d忽略版本号安装(允许降级)、-l锁定应用(Android apk forward lock)):
#关于Android apk forward lock可查看http://developer.android.com/guide/appendix/market-filters.html
adb shell install app
#为特定用户安装软件包(用于多开应用)
adb install --user <userId> <apk_path>
#比如将已经安装在userId=0的应用,安装到userId=999的用户中
adb shell pm install -r --user 999 `adb shell pm path com.tencent.mm | awk -F':' '{print $2}'`
#卸载app:
adb shell uninstall <packageName>
#卸载系统app(-k 表示保存数据):
adb shell pm uninstall -k --user 0 <packageName>
#恢复卸载的app
adb shell cmd package install-existing <packageName>
#启用app:
adb shell pm enable <packageName>
#为特定用户启用app
adb shell pm enable --user <userId> <packageName>
#停用app(方式1):
adb shell pm disable <packageName>
#停用app(方式2):
adb shell pm disable-user <packageName>
#为特定用户停用app
adb shell pm disable --user <userId> <packageName>
#隐藏app(提示没有权限可能需要su):
adb shell pm hide <packageName>
#取消隐藏app:
adb shell pm unhide <packageName>
#去除app权限:
adb shell pm revoke <packageName>
#查看app路径:
adb shell pm path <packageName>

#截图
adb shell screencap /storage/emulated/0/test.png
#录屏(要结束录屏的话就按ctrl+c,或者可以设置最大录屏时间,单位是秒;默认比特率为4Mbps,可以通过--bit-rate更改;通过添加--bugreport参数还可以添加时间戳水印)
adb shell screenrecord --time-limit=120 --bit-rate 6000000 /mnt/sdcard/Download/test.mp4

#从手机提取文件(1为手机路径,2为电脑路径):
adb pull <path1> <path2>
#传送文件到手机(1为电脑路径,2为手机路径):
adb push <path1> <path2>

#将日志打印到电脑上
adb logcat > D:\log.txt
#获取当前打开的APP的包名和activity
adb shell dumpsys window | adb shell grep mFocusedApp
#获取手机内存信息
adb shell cat /proc/meminfo
#获取手机存储信息
adb shell df

#获取手机的序列号(两种方式)
adb get-serialno
adb shell getprop ro.serialno
#获取手机的IMEI(两种方式)
adb shell dumpsys iphonesubinfo
adb shell getprop gsm.baseband.imei
#获取手机厂商名称
adb shell getprop ro.product.brand
#获取手机设备类型
adb shell getprop ro.product.model
#获取Android版本
adb shell getprop ro.build.version.release
#获取api版本
adb shell getprop ro.build.version.sdk
#查看手机的分辨率(两种方式)
adb shell wm size
adb shell dumpsys window | adb shell grep init
#获取手机物理密度
adb shell wm density
#查看电池信息
adb shell dumpsys battery


#查看连接fastboot的设备
fastboot devices

#重启到系统
fastboot reboot
#重启到bootloader(注意部分机型这样做可能会导致系统损坏)
fastboot reboot bootloader
#重启到recovery(注意部分机型这样做可能会导致系统损坏)
fastboot reboot recovery
#刷入ROM(不同机型输入方式不同)
fastboot update update.zip

#oem解锁(不同机型解锁方式可能不同):
fastboot oem unlock
fastboot oem lock

#临时REC(比如TWRP,注意,部分机型的TWRP要刷在vendor_boot或recovery分区):
fastboot boot twrp-xxx.img
#使用sideload方式刷入永久REC(需要先进临时REC并且使用adb sideload功能):
adb sideload twrp-installer-xxx.zip

#直接通过fastboot刷入boot.img(比如用Magisk修补过的boot文件):
fastboot flash boot boot.img
#其他分区同理:
fastboot flash system system.img
#VAB分区时(不同机型的logo分区名字可能不同):
fastboot flash logo_a logo.img
fastboot flash logo_b logo.img
#擦除分区:
fastboot erase system
fastboot erase userdata
fastboot erase metadata
fastboot erase cache

#切换活动槽位为a或b(适用VAB分区的手机)
fastboot set_active a
fastboot set_active b
#adb可以看当前活动槽位
adb shell getprop ro.boot.slot_suffix

#删除所有magisk模块
adb wait-for-device shell magisk --remove-modules

APK-Splits的安装

方法1,解压.apks文件,得到若干个.apk文件,这里假设分成base.apk、split_config.xxhdpi.apk、split_config.arm64_v8a.apk三部分,然后将这些.apk文件文件复制到手机里,这里我们放到/sdcard/tmp/目录下:

# 进入Shell命令行模式
adb shell
# 创建安装session
# (如果已经安装了base.apk,后续不用再装,但这里要使用包名来创建:pm install-create -r -p com.google.android.gm)
pm install-create
# 此时会返回一个结果,比如Success: created install session [1635978285],后续需使用该session ID
pm install-write 1635978285 base.apk /sdcard/tmp/base.apk
pm install-write 1635978285 split_config.xxhdpi.apk /sdcard/tmp/split_config.xxhdpi.apk
pm install-write 1635978285 split_config.arm64_v8a.apk /sdcard/tmp/split_config.arm64_v8a.apk
# 完成写入所有APK后,执行合并安装
pm install-commit 1635978285

方法2,使用官方提供的bundletool.jar安装,需先配置好Java环境:

# 先使用adb devices确认设备已连接
java -jar <bundletool.jar的路径> install-apks --apks=<.apks文件路径>

备注:Google Play Store下载的应用是.aab格式,.aab.apks命令:

java -jar bundletool.jar build-apks --bundle=xxx.aab --output=xxx.apks
# 或
java -jar bundletool.jar build-apks --bundle=xxx.aab --output=xxx.apks --ks=xxxx.jks --ks-pass=pass:证书密码 --ks-key-alias=证书别名 --key-pass=pass:证书别名密码

备份应用命令adb backup [-f <file>] [-apk|-noapk] [-shared|-noshared] [-all] [-system|nosystem] [<packages>]

比如备份软件及数据adb backup -f filename.ab -apk -shared packagesName ,恢复就adb restore <filename.ab>

js生成字符串MD5

// 字符串md5加密,bit指定16位或32位,输出小写,要大写调用字符串的toUpperCase()
function md5(string,bit) {
    function md5_RotateLeft(lValue, iShiftBits) {
        return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));
    }
    function md5_AddUnsigned(lX, lY) {
        var lX4, lY4, lX8, lY8, lResult;
        lX8 = (lX & 0x80000000);
        lY8 = (lY & 0x80000000);
        lX4 = (lX & 0x40000000);
        lY4 = (lY & 0x40000000);
        lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);
        if (lX4 & lY4) {
            return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
        }
        if (lX4 | lY4) {
            if (lResult & 0x40000000) {
                return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
            } else {
                return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
            }
        } else {
            return (lResult ^ lX8 ^ lY8);
        }
    }
    function md5_F(x, y, z) {
        return (x & y) | ((~x) & z);
    }
    function md5_G(x, y, z) {
        return (x & z) | (y & (~z));
    }
    function md5_H(x, y, z) {
        return (x ^ y ^ z);
    }
    function md5_I(x, y, z) {
        return (y ^ (x | (~z)));
    }
    function md5_FF(a, b, c, d, x, s, ac) {
        a = md5_AddUnsigned(a, md5_AddUnsigned(md5_AddUnsigned(md5_F(b, c, d), x), ac));
        return md5_AddUnsigned(md5_RotateLeft(a, s), b);
    };
    function md5_GG(a, b, c, d, x, s, ac) {
        a = md5_AddUnsigned(a, md5_AddUnsigned(md5_AddUnsigned(md5_G(b, c, d), x), ac));
        return md5_AddUnsigned(md5_RotateLeft(a, s), b);
    };
    function md5_HH(a, b, c, d, x, s, ac) {
        a = md5_AddUnsigned(a, md5_AddUnsigned(md5_AddUnsigned(md5_H(b, c, d), x), ac));
        return md5_AddUnsigned(md5_RotateLeft(a, s), b);
    };
    function md5_II(a, b, c, d, x, s, ac) {
        a = md5_AddUnsigned(a, md5_AddUnsigned(md5_AddUnsigned(md5_I(b, c, d), x), ac));
        return md5_AddUnsigned(md5_RotateLeft(a, s), b);
    };
    function md5_ConvertToWordArray(string) {
        var lWordCount;
        var lMessageLength = string.length;
        var lNumberOfWords_temp1 = lMessageLength + 8;
        var lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64;
        var lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16;
        var lWordArray = Array(lNumberOfWords - 1);
        var lBytePosition = 0;
        var lByteCount = 0;
        while (lByteCount < lMessageLength) {
            lWordCount = (lByteCount - (lByteCount % 4)) / 4;
            lBytePosition = (lByteCount % 4) * 8;
            lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition));
            lByteCount++;
        }
        lWordCount = (lByteCount - (lByteCount % 4)) / 4;
        lBytePosition = (lByteCount % 4) * 8;
        lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition);
        lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
        lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
        return lWordArray;
    };
    function md5_WordToHex(lValue) {
        var WordToHexValue = "", WordToHexValue_temp = "", lByte, lCount;
        for (lCount = 0; lCount <= 3; lCount++) {
            lByte = (lValue >>> (lCount * 8)) & 255;
            WordToHexValue_temp = "0" + lByte.toString(16);
            WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length - 2, 2);
        }
        return WordToHexValue;
    };
    function md5_Utf8Encode(string) {
        string = string.replace(/\r\n/g, "\n");
        var utftext = "";
        for (var n = 0; n < string.length; n++) {
            var c = string.charCodeAt(n);
            if (c < 128) {
                utftext += String.fromCharCode(c);
            } else if ((c > 127) && (c < 2048)) {
                utftext += String.fromCharCode((c >> 6) | 192);
                utftext += String.fromCharCode((c & 63) | 128);
            } else {
                utftext += String.fromCharCode((c >> 12) | 224);
                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                utftext += String.fromCharCode((c & 63) | 128);
            }
        }
        return utftext;
    };
    var x = Array();
    var k, AA, BB, CC, DD, a, b, c, d;
    var S11 = 7, S12 = 12, S13 = 17, S14 = 22;
    var S21 = 5, S22 = 9, S23 = 14, S24 = 20;
    var S31 = 4, S32 = 11, S33 = 16, S34 = 23;
    var S41 = 6, S42 = 10, S43 = 15, S44 = 21;
    string = md5_Utf8Encode(string);
    x = md5_ConvertToWordArray(string);
    a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476;
    for (k = 0; k < x.length; k += 16) {
        AA = a; BB = b; CC = c; DD = d;
        a = md5_FF(a, b, c, d, x[k + 0], S11, 0xD76AA478);
        d = md5_FF(d, a, b, c, x[k + 1], S12, 0xE8C7B756);
        c = md5_FF(c, d, a, b, x[k + 2], S13, 0x242070DB);
        b = md5_FF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE);
        a = md5_FF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF);
        d = md5_FF(d, a, b, c, x[k + 5], S12, 0x4787C62A);
        c = md5_FF(c, d, a, b, x[k + 6], S13, 0xA8304613);
        b = md5_FF(b, c, d, a, x[k + 7], S14, 0xFD469501);
        a = md5_FF(a, b, c, d, x[k + 8], S11, 0x698098D8);
        d = md5_FF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF);
        c = md5_FF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1);
        b = md5_FF(b, c, d, a, x[k + 11], S14, 0x895CD7BE);
        a = md5_FF(a, b, c, d, x[k + 12], S11, 0x6B901122);
        d = md5_FF(d, a, b, c, x[k + 13], S12, 0xFD987193);
        c = md5_FF(c, d, a, b, x[k + 14], S13, 0xA679438E);
        b = md5_FF(b, c, d, a, x[k + 15], S14, 0x49B40821);
        a = md5_GG(a, b, c, d, x[k + 1], S21, 0xF61E2562);
        d = md5_GG(d, a, b, c, x[k + 6], S22, 0xC040B340);
        c = md5_GG(c, d, a, b, x[k + 11], S23, 0x265E5A51);
        b = md5_GG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA);
        a = md5_GG(a, b, c, d, x[k + 5], S21, 0xD62F105D);
        d = md5_GG(d, a, b, c, x[k + 10], S22, 0x2441453);
        c = md5_GG(c, d, a, b, x[k + 15], S23, 0xD8A1E681);
        b = md5_GG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8);
        a = md5_GG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6);
        d = md5_GG(d, a, b, c, x[k + 14], S22, 0xC33707D6);
        c = md5_GG(c, d, a, b, x[k + 3], S23, 0xF4D50D87);
        b = md5_GG(b, c, d, a, x[k + 8], S24, 0x455A14ED);
        a = md5_GG(a, b, c, d, x[k + 13], S21, 0xA9E3E905);
        d = md5_GG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8);
        c = md5_GG(c, d, a, b, x[k + 7], S23, 0x676F02D9);
        b = md5_GG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A);
        a = md5_HH(a, b, c, d, x[k + 5], S31, 0xFFFA3942);
        d = md5_HH(d, a, b, c, x[k + 8], S32, 0x8771F681);
        c = md5_HH(c, d, a, b, x[k + 11], S33, 0x6D9D6122);
        b = md5_HH(b, c, d, a, x[k + 14], S34, 0xFDE5380C);
        a = md5_HH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44);
        d = md5_HH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9);
        c = md5_HH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60);
        b = md5_HH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70);
        a = md5_HH(a, b, c, d, x[k + 13], S31, 0x289B7EC6);
        d = md5_HH(d, a, b, c, x[k + 0], S32, 0xEAA127FA);
        c = md5_HH(c, d, a, b, x[k + 3], S33, 0xD4EF3085);
        b = md5_HH(b, c, d, a, x[k + 6], S34, 0x4881D05);
        a = md5_HH(a, b, c, d, x[k + 9], S31, 0xD9D4D039);
        d = md5_HH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5);
        c = md5_HH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8);
        b = md5_HH(b, c, d, a, x[k + 2], S34, 0xC4AC5665);
        a = md5_II(a, b, c, d, x[k + 0], S41, 0xF4292244);
        d = md5_II(d, a, b, c, x[k + 7], S42, 0x432AFF97);
        c = md5_II(c, d, a, b, x[k + 14], S43, 0xAB9423A7);
        b = md5_II(b, c, d, a, x[k + 5], S44, 0xFC93A039);
        a = md5_II(a, b, c, d, x[k + 12], S41, 0x655B59C3);
        d = md5_II(d, a, b, c, x[k + 3], S42, 0x8F0CCC92);
        c = md5_II(c, d, a, b, x[k + 10], S43, 0xFFEFF47D);
        b = md5_II(b, c, d, a, x[k + 1], S44, 0x85845DD1);
        a = md5_II(a, b, c, d, x[k + 8], S41, 0x6FA87E4F);
        d = md5_II(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0);
        c = md5_II(c, d, a, b, x[k + 6], S43, 0xA3014314);
        b = md5_II(b, c, d, a, x[k + 13], S44, 0x4E0811A1);
        a = md5_II(a, b, c, d, x[k + 4], S41, 0xF7537E82);
        d = md5_II(d, a, b, c, x[k + 11], S42, 0xBD3AF235);
        c = md5_II(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB);
        b = md5_II(b, c, d, a, x[k + 9], S44, 0xEB86D391);
        a = md5_AddUnsigned(a, AA);
        b = md5_AddUnsigned(b, BB);
        c = md5_AddUnsigned(c, CC);
        d = md5_AddUnsigned(d, DD);
    }
    if(bit==32){
        return (md5_WordToHex(a) + md5_WordToHex(b) + md5_WordToHex(c) + md5_WordToHex(d)).toLowerCase();
    }
    return (md5_WordToHex(b) + md5_WordToHex(c)).toLowerCase();
}