选中桌面中的计算机图标,右键,点击管理
系统工具
本地用户和组
用户
选中Administrator,然后重命名
重启电脑
win+r 打开运行
输入 gpedit.msc 打开策略组
计算机配置
windows设置
安全设置
本地策略
安全选项
拉到最下面
双击这个选选项 重命名系统管理员帐户
重启电脑
win+r 打开运行
输入 netplwiz
选中Administrator,然后双击,然后修改
重启电脑
win+r 打开运行
输入 gpedit.msc 打开策略组
计算机配置
windows 设置
安全设置
本地策略
安全选项
拉到最下面
禁用 使用空密码的本地账户只允许控制台登录
电脑提示“账户名与安全标识间无任何映射完成” 一般是修改玩用户名后没有重启导致的。
因为公司的电脑不能设密码,同时我又想远程桌面公司的电脑,考虑到安全问题,不能用默认用户名裸奔,所以修改用户名和设置无密码的远程桌面
需要一个在 wall 以外的服务器
ss 的各个版本 https://github.com/shadowsocks/shadowsocks/wiki/Feature-Comparison-across-Different-Versions
python -m pip install shadowsocks
# 如果上面那句下载失败,可以尝试用这句安装
python -m pip install https://github.com/shadowsocks/shadowsocks/archive/master.zip -U
# 如果上面那句还是下载失败,可以尝试先把 master.zip 文件下载到本地,再安装
ssserver -p 61813 -k windows@163.qq -m aes-256-cfb
-p 是端口号
-k 是密码
-m 是加密方式
上面那条命令需要在 服务器的策略组 和 防火墙 放行 61813 端口
https://download.libsodium.org/libsodium/releases/
python -m pip install --upgrade shadowsocks
# 如果上面那句更新失败,可以尝试这样更新,先卸载再重新安装,卸载前记得先备份当前的版本
python -m pip show shadowsocks
python -m pip uninstall shadowsocks
python -m pip install https://github.com/shadowsocks/shadowsocks/archive/master.zip -U
https://github.com/shadowsocks/shadowsocks/wiki/Shadowsocks-%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E
安装
apt update
apt install shadowsocks-libev
作为服务端运行
ss-server -s 0.0.0.0 -p 61813 -k windows@163.qq -m aes-256-cfb
或者
ss-server -c config.json
{
"server": "0.0.0.0",
"server_port": 61813,
"password": "windows@163.qq",
"method": "aes-256-gcm"
}
对应的文档 https://github.com/shadowsocks/shadowsocks-libev/blob/master/doc/ss-server.asciidoc
作为客户端运行
ss-local -s host -p 61813 -k windows@163.qq -m aes-256-cfb -l 1080
或者
ss-local -c config.json
{
"server": "host",
"server_port": 61813,
"local_address": "0.0.0.0",
"local_port": 1080,
"password": "windows@163.qq",
"timeout": 600,
"method": "aes-256-gcm"
}
对应的文档 https://github.com/shadowsocks/shadowsocks-libev/blob/master/doc/ss-local.asciidoc
在命令行里加入这个环境变量
export ALL_PROXY=socks5h://127.0.0.1:1080
检测代理是否有效
curl -v -L www.baidu.com
curl -v -L www.cip.cc
curl -v -L ip-api.com
curl -i -v -L --proxy socks5://127.0.0.1:1080 ip-api.com
curl -i -v -L --proxy http://127.0.0.1:1081 ip-api.com
curl -i -v -L --proxy http://127.0.0.1:1081 https://registry-1.docker.io/v2/
通过 cargo 安装
curl -L -O https://static.rust-lang.org/dist/rust-1.91.1-x86_64-unknown-linux-gnu.tar.xz
tar -xJf rust-1.91.1-x86_64-unknown-linux-gnu.tar.xz
cd rust-1.91.1-x86_64-unknown-linux-gnu.tar.xz
bash install.sh
cargo install shadowsocks-rust
直接下二进制文件
curl -L -O https://github.com/shadowsocks/shadowsocks-rust/releases/download/v1.24.0/shadowsocks-v1.24.0.x86_64-unknown-linux-gnu.tar.xz
tar -xJf shadowsocks-v1.24.0.x86_64-unknown-linux-gnu.tar.xz
安装完后,通过配置文件启动客户端
vi ss-local-config.json
{
// Server configuration
// listen on :: for dual stack support, no need add [] around.
"server": " ",
// Change to use your custom port number
"server_port": 61813,
"method": " ",
"password": "windows@163.qq",
// Server: TCP socket timeout in seconds.
// Client: TCP connection timeout in seconds.
// Omit this field if you don't have specific needs.
"timeout": 7200,
// Extended multiple local configuration
"locals": [
{
// SOCKS5, SOCKS4/4a local server
"protocol": "socks",
// Basic configuration, a SOCKS5 local server
"local_address": "0.0.0.0",
"local_port": 1080,
// OPTIONAL. Setting the `mode` for this specific local server instance.
// If not set, it will derive from the outer `mode`
"mode": "tcp_only"
},
{
// HTTP local server (feature = "local-http")
"protocol": "http",
// Listen address
"local_address": "0.0.0.0",
"local_port": 1081
}
]
}
./sslocal -c ss-local-config.json --worker-threads=4 -d
通过 docker 运行
docker run --name sslocal-rust \
--restart always \
-p 1080:1080/tcp \
-p 1081:1081/tcp \
-v ~/ss-local-config.json:/etc/shadowsocks-rust/config.json:ro \
ghcr.io/shadowsocks/sslocal-rust:latest \
sslocal -c /etc/shadowsocks-rust/config.json
<!-- 在本地编译 通过docker安装 安装依赖 yum install epel-release -y yum install gcc gettext autoconf libtool automake make pcre-devel asciidoc xmlto c-ares-devel libev-devel libsodium-devel mbedtls-devel -y 下载源码 curl -L -O https://github.com/shadowsocks/shadowsocks-rust/archive/refs/tags/v1.23.5.tar.gz 编译 安装 curl https://sh.rustup.rs -sSf | sh curl -L -v -o rustup.sh https://sh.rustup.rs sh rustup.sh cargo install shadowsocks-rust curl -L -v -O https://static.rust-lang.org/dist/rust-1.93.0-x86_64-unknown-linux-gnu.tar.xz curl -L -O https://static.rust-lang.org/dist/rust-1.93.0-x86_64-unknown-linux-gnu.tar.xz tar -Jxf rust-1.93.0-x86_64-unknown-linux-gnu.tar.xz cd rust-1.93.0-x86_64-unknown-linux-gnu.tar bash install.sh docker pull ghcr.io/shadowsocks/sslocal-rust:latest docker run --name sslocal-rust \ --restart always \ -p 1080:1080/tcp \ -v /path/to/config.json:/etc/shadowsocks-rust/config.json \ -dit ghcr.io/shadowsocks/sslocal-rust:latest docker run --name sslocal-rust \ --restart always \ -p 1080:1080/tcp \ -dit ghcr.io/shadowsocks/sslocal-rust:latest \ -s host -p 61813 -k windows@163.qq-m chacha20-ietf-poly1305 -l 1080 docker run --rm -it \ --entrypoint=/bin/sh \ ghcr.io/shadowsocks/sslocal-rust:latest docker run --name sslocal-rust \ --restart always \ -p 1080:1080/tcp \ ghcr.io/shadowsocks/sslocal-rust:latest \ sslocal -s host:61813 -k windows@163.qq -m chacha20-ietf-poly1305 -b 0.0.0.0:1080 docker run --name sslocal-rust \ --restart always -d \ -p 1080:1080/tcp \ -v ~/ss-local-config.json:/etc/shadowsocks-rust/config.json:ro \ ghcr.io/shadowsocks/sslocal-rust:latest \ sslocal -c /etc/shadowsocks-rust/config.json docker run --rm -it \ --entrypoint=/bin/sh \ -v ~/ss-local-config.json:/etc/shadowsocks-rust/config.json \ ghcr.io/shadowsocks/sslocal-rust:latest docker pull busybox:1.37-uclibc docker inspect --format='{{json .Config.Entrypoint}}' nohup ss-local -s host -p 61813 -k windows@163.qq -m chacha20-ietf-poly1305 -l 1080 >> out.log 2>&1 & ./sslocal -c ss-local-config.json --worker-threads=4 -d 用于定时启动的脚本 ``` # ssserver-startup.ps1 $host.UI.RawUI.WindowTitle="ssserver" ssserver -p 61304 -k windows@163.qq -m chacha20-ietf-poly1305 ``` 用于定时重启的脚本 ``` # ssserver-restart.ps1 Get-Process | Where-Object {$_.MainWindowTitle -eq "ssserver"} ; Start-Sleep -Seconds 1; Get-Process | Where-Object {$_.MainWindowTitle -eq "ssserver" -and $_.Name -eq "powershell"} | Stop-Process ; Start-Sleep -Seconds 1; Get-Process | Where-Object {$_.MainWindowTitle -eq "ssserver" -and $_.Name -eq "python"} | Stop-Process ; Start-Sleep -Seconds 1; Get-Process | Where-Object {$_.MainWindowTitle -eq "ssserver"} | Stop-Process ; Start-Sleep -Seconds 1; powershell -File "C:\Users\Administrator\Desktop\ssserver-startup.ps1" ; ``` 用于新建计划任务的命令 ``` Register-ScheduledTask -TaskName "ssserver-restart" -Trigger (New-ScheduledTaskTrigger -Daily -At 2am) -Action (New-ScheduledTaskAction -Execute "powershell" -Argument " -File `"C:\Users\Administrator\Desktop\ssserver-restart.ps1`" "); ``` -->
安装
sudo apt install privoxy
配置 在这个文件 /etc/privoxy/config 的最后追加内容
# 转发设置为本地socks代理
forward-socks5 / 127.0.0.1:1080 .
# 本地http代理监听端口
listen-address 127.0.0.1:1081
重启
systemctl restart privoxy
systemctl enable privoxy
在命令行里加入环境变量
export http_proxy=http://127.0.0.1:1081; \
export HTTPS_PROXY=http://127.0.0.1:1081; \
export ALL_PROXY=socks5h://127.0.0.1:1080
export http_proxy= ; \
export HTTPS_PROXY= ; \
export ALL_PROXY=
export -n http_proxy ; \
export -n HTTPS_PROXY ; \
export -n ALL_PROXY
<!-- 可以启用调试模式。在配置文件中添加以下内容: debug 1 # 显示启动信息 debug 2 # 显示客户端请求信息 debug 4 # 显示连接详细信息 启动调式模式后,可以这样查看日志,要注意 privoxy 要有写入权限 cat /var/log/privoxy/logfile -->
||| |-|-| |Visual Studio 6.0|VC6| |Visual Studio .NET 2002|VC7.0| |Visual Studio .NET 2003|VC7.1| |Visual Studio 2005|VC8| |Visual Studio 2008|VC9| |Visual Studio 2010|VC10| |Visual Studio 2012|VC11| |Visual Studio 2013|VC12| |Visual Studio 2015|VC14| |Visual Studio 2017|VC15| |Visual Studio 2019|VS16| |Visual Studio 2022|VS17|
||| |-|-| |5.2|vc6| |5.3|vc9| |5.4|vc9| |5.5|vc11| |5.6|vc11| |7.0|vc14| |7.1|vc14| |7.2|vc15| |7.3|vc15| |7.4|vc15| |8.0|vs16| |8.1|vs16|
U盘 弹出失败的原因是进程占用了 U盘 ,只要占用 U盘 的进程都不在占用 U盘 或 都结束了, U盘 就可以安全地弹出了。
所以,让 U盘 安全地弹出的关键是找到占用 U盘 的进程。
当占用 U盘 的进程结束后,有时立即弹出 U盘 还是会失败的,这时再等待五六秒,再试一次弹出 U盘 就可以了。
可以安全退出 U盘 时也不要马上拔 U盘 ,最好等个五六秒再拔 U盘 。
这是各种方法的总结
笔者通常在直接弹出 U盘 失败后,会多试几次,然后通过 日志 找到对应的进程,然后通过 任务管理器 结束对应的进程,如果结束进程失败,还是会再次在网上搜索解决方法。 脱机 和 关闭写缓存都有一点副作用; 关闭文件夹,重启 explorer.exe ,注销,关机,这类都有点麻烦。
其实就三种套路
wsl1 和 wsl1 之前的 sfu/sua 是子系统, wsl2 其实算是虚拟机,其它的都是运行在 win32 上的兼容层。 nt 内核其实是有三个子系统 win32 ,os/2 和 posix ,只是除了 win32 其它两个都没有什么存在感。
所谓的 linux 环境,除了需要 bash 之外,还需要各种 linux 的工具,还需要处理管道,还需要处理文件名和路径的问题。 还有各种 linux api 的问题(但不写需要编译的代码,只使用环境中的工具,其实这个问题可以忽略的)。
<!-- DJGPP DJ's GNU Programming Platform DJ的GNU编程平台 cygwin 是最早的,使用兼容层 cygwin1.dll mingw 从 cygwin 发展而来的,不使用兼容层,编译的是原生的 windows程序 MinGW诞生是因为开发者想要: 1. 在Windows上使用GCC工具链 2. 但不想要Cygwin的POSIX模拟层 3. 生成完全原生的Windows程序 mingw-w64 从 mingw 发展而来的,直接原因是因为 mingw 不支持 64位 MSYS 从 cygwin 发展而来的,使用一个精简过的 cygwin1.dll , dll文件名是 msys-1.0.dll 本着注重 Minimal(最小化)的原则, 其只提供了最基本的 API, 其兼容性相对于 Cygwin 较差 MSYS2 从 MSYS 发展而来的,dll文件名是 msys-2.0.dll Git for Windows 和 TDM-GCC 都是基于 mingw-w64 TDM-GCC 是一个包含 gcc 的编译工具链,一些windows下的ide会集成 TDM-GCC 作为 c语言的编译器 cygwin 是 Cygnus 的产品 cygwin 中的 cyg 应该是代表公司名称 Cygnus Cygnus, Your GNU Support 递归式首字母缩写词 1999年11月15日,Cygnus Solutions宣布将与红帽公司合并,2000年初起不再作为单独的公司存在。 MinGW Minimalist GNU for Windows MSYS Minimal SYStem Minimalist adj. 最低必须限度的 Minimal adj. 极小的 gnuwin32/gnuwin64/UnxUtils 这类都是工具的集合,本质上依然是 cygwin 或 MinGW -->
http://www.ffmpeg.org/download.html
ffmpeg -i "缓存视频文件的文件名" "转换格式后的文件名"
https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
选择,Windows 64 位
打开下载的 exe 文件,一路点 next 直到安装完毕
C:\Program Files\Java\jdk1.8.0_161
%JAVA_HOME%\bin
%JAVA_HOME%\jre\bin
%JAVA_HOME%\lib
https://tomcat.apache.org/download-90.cgi
选择,core,Windows 64 位
如果出现这种错误
无法启动此程序,因为计算机中丢失 libui.dll,尝试重新安装该程序以解决此问题。
这个提示出现说明你没有放入 libui 和 pthreadVC2 文件到 php 的根目录下
remote terminal <----> ssh server <----> shell <----> tmux client <----> tmux server <----> shell
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
// 另一种关闭文件描述符的方法,但 getdtablesize() 来自 unistd.h
// for(i = 0; i < getdtablesize(); i++)
// {
// close(i);
// }
vi deamon.c#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>
int main(int argc, char *argv[])
{
pid_t pid = fork();
if (pid > 0) {
exit(0); // 1.父进程退出
} else if (pid == 0) {
// 2.变为会话组长,脱离了控制终端 setsid()调用成功后,进程成为新的会话组长和新的进程组长,并与原来的登录会话和进程组脱离
setsid();
// 3.改变进程的工作目录
chdir("/var");
// 4. 重置文件掩码
umask(0);
// 5. 关闭文件描述符
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
// 6. 执行核心操作
// 每三秒一条记录到日志文件里,执行100次
int fd = open("/var/temp-deamon-log.txt", O_CREAT | O_WRONLY | O_APPEND, 0664);
int i;
for (i = 0; i < 100; i++) {
sleep(3);
time_t curtime;
time(&curtime);
char* pt = ctime(&curtime);
write(fd, pt, strlen(pt) + 1);
}
close(fd);
}
return EXIT_SUCCESS;
}
gcc deamon.c && \
./a.out && \
sleep 30 && \
cat -n /var/temp-deamon-log.txt && \
kill `ps -elf | grep a.out | awk '{print $4}'` && \
rm /var/temp-deamon-log.txt
>> out.log 把输出追加到 out.log 文件里2>&1 把 stderr 重定向到 stdoutnohup php queue.php >> out.log 2>&1 &/etc/systemd/system 目录新建一个文件 myDaemon.service[Unit]
Description=myDaemon service
[Service]
# service 的类型
Type=simple
# 退出后马上重启
Restart=always
# 这里的 bash 路径和脚本路径都必须是绝对路径
ExecStart=/bin/bash /root/myDaemon.sh
[Install]
# 开机启动时的依赖项,大多数情况下都是填这个
WantedBy=multi-user.target
# 重新加载 systemctl 配置
systemctl daemon-reload
# 启动 myDaemon.service
systemctl start myDaemon.service
# myDaemon.service 加入到开机启动中
systemctl enable myDaemon.service
* * * * * php queue.php >> out.log 2>&1编译的四个步骤
编译的四个步骤对应的 gcc 命令
gcc -E test.c -o test.i
gcc -S test.i -o test.s
gcc -c test.s -o test.o
gcc test.o -o test
实际上 gcc 这个命令只是这些后台程序的包装,它会根据不同的参数要求去调用预处理器cpp、预编译程序cc1、汇编器as、链接器ld
cpp test.c -o test.i
cc1 test.i -o test.s
as test.s -o test.o
ld test.o -o test
GNU 工具链
其它
# 没使用 pkg-config
gcc test.c -o test -I/usr/local/Cellar/opencv3/3.1.0_4/include/opencv -I/usr/local/Cellar/opencv3/3.1.0_4/include
# 使用了 pkg-config
gcc test.c -o test $(pkg-config opencv --cflags)
<!-- bsdmainutils net-tools 和 iputils-ping 和 iproute2 dnsutils host dig nslookup -->
参考
感觉 GNU 真的除了内核之外,什么都有了。
用来测试网站对 ipv6 的支持,也可以用来查看 DNSSEC 的支持 https://ipv6.ustc.edu.cn/onlinechecklog.php
python 的 json.tool ,好像 python2 和 3 都可以这样用
echo '{ "name": "xiaohong", "age": 18 }' | python -m json.tool
json_pp , windwos 的 git bash 和 大多数 linux 发行版都有这个工具
echo '{ "name": "xiaohong", "age": 18 }' | json_pp
jq , 虽然大多数 linux 发行版都没有这个工具,但中文互联网环境下有好多文章都推荐这个
php 的命令行,标准输入中一定要有数据,不然会一直等待;同样地 python 或 node 也可以实现类似的
echo '{ "name": "xiaohong", "age": 18, "chinese character":"汉字" }' | \
php -r 'print(json_encode(json_decode(file_get_contents("php://stdin")),JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE));';
PowerShell 的 ConvertFrom-Json 和 ConvertTo-Json ,这两个要组合来使用
echo '{"type":"image","offset":0,"count":20}' | ConvertFrom-Json | ConvertTo-Json
配合 curl 使用
curl -s -k https://localhost/dev.json | json_pp
curl -s -k https://localhost/dev.json | python -m json.tool
配合 PowerShell 的 Invoke-WebRequest 使用
Invoke-WebRequest https://localhost/dev.json -UseBasicParsing -SkipCertificateCheck | Select -ExpandProperty Content | ConvertFrom-Json | ConvertTo-Json
Invoke-WebRequest https://localhost/dev.json -UseBasicParsing -SkipCertificateCheck | Select -ExpandProperty Content | python -m json.tool
如果 Invoke-WebRequest 出现了这种错误。
因为 Internet Explorer 引擎不可用,或者 Internet Explorer 的首次启动配置不完整
可以尝试以下步骤来解决
windows10 之前的系统在修改 path 时要注意分号 ;
在 JDK1.5 以后,classpath 并不是必须配置了,在 JDK1.5 之前,是没有办法在当前目录下加载类的(找不到 JDK 目录下 lib 文件夹中的 .jar 文件),所以我们需要通过配置 classpath ,但 JDK1.5 之后, JRE 能自动搜索目录下类文件,并且加载 dt.jar 和 tool.jar 的类。 dt.jar 是关于运行环境的类库,主要是用于 swing 的包,如果不使用可以不配置。 tools.jar 是工具类库。
编译和运行时可以通过参数 -classpath 指定 classpath 的路径,例如这样
javac -encoding UTF-8 -classpath .;./junit4.jar;./org.hamcrest.core_1.3.0.jar AaaTest.java JunitRunner.java
java -Dfile.encoding=UTF-8 -classpath .;./junit4.jar;./org.hamcrest.core_1.3.0.jar JunitRunner
python 的 cgi 模块在 3.15 被移除了 https://docs.python.org/zh-cn/3.12/library/cgi.html https://peps.python.org/pep-0594/#cgi
3.14 是唯一一个既有 cgi 也有 tls 的版本
python 一行命令启动 http 服务
# 最简单的 http 服务
python -m http.server
# 指定端口号的 http 服务
python -m http.server 8081
# 有 cgi 的 http 服务
python -m http.server --cgi
# 有 cgi 的和指定端口号的 http 服务
python -m http.server --cgi 8081
# 有 cgi 的,指定端口号的和指定ip地址的 http 服务
python -m http.server --cgi 8081 --bind 127.0.0.1
# 有 cgi 的,指定端口号的,指定ip地址的和指定站点根目录的 http 服务
python -m http.server --cgi 8081 --bind 127.0.0.1 --directory _book
请求 cgi 脚本的例子
curl 127.0.0.1:8000/cgi-bin/test.py
cgi 脚本的例子
#!/usr/bin/python3
print ("Content-type:text/html")
print () # 空行,告诉服务器结束头部
print ('<html>')
print ('<head>')
print ('<meta charset="utf-8">')
print ('<title>Hello Word</title>')
print ('</head>')
print ('<body>')
print ('<h2>Hello Word!</h2>')
print ('</body>')
print ('</html>')
#!/usr/bin/python3
print ("Content-type: application/json")
print () # 空行,告诉服务器结束头部
print ('{"result": "this is a test"}')
这个例子大致相当于这个命令 python -m http.server 8888
from http.server import HTTPServer, SimpleHTTPRequestHandler
if __name__ == '__main__':
host = ('0.0.0.0', 8888)
server = HTTPServer(host, SimpleHTTPRequestHandler)
print('Serving HTTP on {host} port {port} (http://{host}:{port}/) ...'.format(host=host[0], port=host[1]))
server.serve_forever()
这个例子大致相当于这个命令 python -m http.server --cgi 8888
from http.server import HTTPServer, CGIHTTPRequestHandler
if __name__ == '__main__':
host = ('0.0.0.0', 8888)
server = HTTPServer(host, CGIHTTPRequestHandler)
print('Serving HTTP on {host} port {port} (http://{host}:{port}/) ...'.format(host=host[0], port=host[1]))
server.serve_forever()
不使用命令行的 http 服务例子,这是单线程的
from http.server import HTTPServer, BaseHTTPRequestHandler
import json
class myHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'application/json')
self.end_headers()
self.wfile.write(json.dumps({'result': 'this is a test'}).encode())
if __name__ == '__main__':
host = ('0.0.0.0', 8888)
server = HTTPServer(host, myHandler)
print('Serving HTTP on {host} port {port} (http://{host}:{port}/) ...'.format(host=host[0], port=host[1]))
server.serve_forever()
不使用命令行的 http 服务例子,这是多线程的
from http.server import HTTPServer, BaseHTTPRequestHandler
from socketserver import ThreadingMixIn
import json
class ThreadingHttpServer(ThreadingMixIn, HTTPServer):
pass
class myHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'application/json')
self.end_headers()
self.wfile.write(json.dumps({'result': 'this is a test'}).encode())
if __name__ == '__main__':
host = ('0.0.0.0', 8888)
server = ThreadingHttpServer(host, myHandler)
print('Serving HTTP on {host} port {port} (http://{host}:{port}/) ...'.format(host=host[0], port=host[1]))
server.serve_forever()
不使用命令行的 http 服务例子,这是多线程的,再加上 cgi 的支持
from http.server import HTTPServer, CGIHTTPRequestHandler
from socketserver import ThreadingMixIn
class ThreadingHttpServer(ThreadingMixIn, HTTPServer):
pass
if __name__ == '__main__':
host = ('0.0.0.0', 8888)
server = ThreadingHttpServer(host, CGIHTTPRequestHandler)
print('Serving HTTP on {host} port {port} (http://{host}:{port}/) ...'.format(host=host[0], port=host[1]))
server.serve_forever()
HTTPServer 和 BaseHTTPRequestHandler 是两个关键的类,一个用于接收 http 请求,一个用于处理请求,其它类基本是派生自这两个类
BaseHTTPRequestHandler -> SimpleHTTPRequestHandler -> CGIHTTPRequestHandler
HTTPServer -> ThreadingHttpServer
参考文档
<!-- java 中类似的命令,来自 jdk18 jep408 java -m jdk.httpserver [-b bind address] [-p port] [-d directory] [-h to show help message] [-o none|default|verbose] ``` java -m jdk.httpserver -b 127.0.0.1 -p 80 java -m jdk.httpserver -b 127.0.0.1 -p 80 -d ~/wwwroot java -m jdk.httpserver -b 127.0.0.1 -p 80 -d ~/wwwroot -o verbose ``` php 中类似的命令 php [options] -S <addr>:<port> [-t docroot] [router] ``` php -S 127.0.0.1:80 php -S 127.0.0.1:80 -t ~/wwwroot php -S 127.0.0.1:80 -t ~/wwwroot router.php php -d xdebug.start_with_request=yes -S 127.0.0.1:80 -t ~/wwwroot router.php ``` ruby -run -e httpd . -p8000 busybox httpd -f -p 8000 go prel nodejs .net 都有类似的一句话服务,但需要安装相应的包 nc 理论上也可以实现,但一行代码会写得非常长 -->
./Lib/site-packages
参考这个文档 https://pip.pypa.io/en/stable/installation/
python 的环境变量,除了安装目录之外,还有一个 Script 目录 但其实一般影响都不大,根目录重要一点
如果没法把 python 加入环境变量,那么每次调用最好都用绝对路径
<!-- alias python=/d/python-3.12.3-embed-amd64/python.exe export PATH=/d/python-3.12.3-embed-amd64:$PATH export PATH=/d/python-3.12.3-embed-amd64/Scripts:$PATH 更新 pip python -m pip install --upgrade pip 查看python的路径 python -m site -->
列出 pip 的所有模块
python -m pip list
列出 python 所有可用的模块
python -c 'import pydoc;pydoc.help("modules")'
这句也有类似的效果,但好像只有 sys 下的模块
python -c 'import sys;print(sys.modules.keys())'
安装命令
python -m pip install tkinter-embed
安装完成后还需要设置这两个环境变量 TCL_LIBRARY TK_LIBRARY
export TCL_LIBRARY="/d/python-3.12.3-embed-amd64/Lib/site-packages/tcl/tcl8.6"
export TK_LIBRARY="/d/python-3.12.3-embed-amd64/Lib/site-packages/tcl/tk8.6"
<!-- python 也可以以这样的方式直接运行 tcl import tkinter tcl_interp = tkinter.Tcl() result = tcl_interp.eval('expr {2 + 3}') # 执行Tcl的expr命令 print(result) # 打印 5 tk = tkinter.Tk() tk.eval('encoding system utf-8') # 要先设置编码,不然 source 命令的编码是 Latin-1 tk.eval('source C:/Users/hello.tcl') # 要把 /d/python-3.12.3-embed-amd64/Lib/site-packages/tk86t.dll 复制到 /d/python-3.12.3-embed-amd64/Lib/site-packages/bin/tk86t.dll ,不然无法运行 source 命令 Tcl (Tool Command Language) Tclsh (Tcl Shell) wish (Windowing Shell) Tkinter 是 tk 的 python binding Tkinter 是 tk 的 python 绑定包 Tcl C API https://www.tcl-lang.org/man/tcl8.6.13/TclLib/contents.htm Tk C API https://www.tcl-lang.org/man/tcl8.6.13/TkLib/contents.htm echo 'puts [info patchlevel]' | tclsh echo "puts hello" | tclsh -encoding utf-8 wish -encoding utf-8 hello.tcl tclsh -encoding utf-8 hello.tcl 不加 -encoding utf-8 会显示乱码 tclsh 要在文件开头加上这句 package require Tk 如果脚本中写了 package require Tk,用 wish 运行也没问题(重复加载会被忽略)。 package require Tk # 设置主窗口标题 wm title . "我的第一个 Tk 窗口" # 创建一个标签 label .lbl -text "你好,世界!" -font {{SimHei} 12 {bold}} # 创建一个按钮,点击后退出程序 button .btn -text "退出" -command {exit} # 使用 pack 布局管理器放置控件 pack .lbl -pady 10 pack .btn -pady 5 直接运行 wish 会有一个交互界面 echo 'tk_messageBox -title "escapedTitle" -message "escapedMessage"' | wish echo 'package require Tk; tk_messageBox -title "escapedTitle" -message "escapedMessage"' | tclsh -->
embed 版的 Python 的模块并不会将工作目录添加到搜索路径中
这会导致一般的引用方式报错
ImportError: attempted relative import with no known parent package
需要用动态导入的方式加上 工作目录,在调用的文件里的开头加上这一句
import sys, os
sys.path.append(os.getcwd())
或者在安装目录下的 python312._pth 文件里加上 工作目录的路径,要用绝对路径
C:/Users/username/project
import sys;sys._exit()
import os;os._exit(0)
import os
import signal
current_pid = os.getpid()
print(f"当前进程的 PID 是: {current_pid}")
os.kill(current_pid, signal.SIGINT)
<!-- python 的类型 数字 numeric 整数 int 浮点数 float 复数 complex 布尔 bool 序列 sequence 不可变序列 immutable-sequences tuple(元组) str(字符串) bytes(字节串) 可变序列 mutable-sequences list(列表) bytearray(字节数组) 集合 set 可变集合 mutable set set(集合) 不可变集合 immutable set frozenset(冻结集合) 映射 mapping dict(字典) 和类型相关的内置函数 bool() bytearray() bytes() complex() dict() float() frozenset() int() list() map() object() range() set() tuple() type() 内置常量 True False None range 是 list 的子类 bool 是 int 的子类 float 是 int 的子类 但 complex 不是 int 的子类 有内置函数的就当是内置类型吧 所有类型都是 类 object 是所有类型的父类 数据模型 https://docs.python.org/zh-cn/3.12/reference/datamodel.html 内置类型 https://docs.python.org/zh-cn/3.14/library/stdtypes.html type(object) 传入一个参数时,返回 object 的类型。 issubclass(class, classinfo) 如果 class 是 classinfo 的子类(直接、间接或 虚的 ),则返回 True。 isinstance(object, classinfo) 如果 object 参数是 classinfo 参数的实例,或者是其 (直接、间接或 虚拟) 子类的实例则返回 True。 则该函数总是返回 False。 推荐使用 isinstance() 内置函数来检测对象的类型,因为它会考虑子类的情况。 python的列表(List)大概等于 C语言中的动态数组 [] python的元组(Tuple)大概等于 C语言中的普通数组 () python的字典(Dictionary)就是键值对,从形式上看,最接近php的数组 {} python的集合(Set)是元素无序的不重复的线性表 python 转换成 exe gui小程序 powershell windows 环境下最容易分享,通常只需要脚本文件即可 如果需要十分傻瓜式启动依然需要转换成 exe ,默认情况下容易有权限的限制 python tk 可以跨平台 如果需要傻瓜式启动依然需要转换成 exe web+后台服务 可以跨平台,甚至 安卓 也能运行 通常有一个命令行窗口,这个对用户其实并不友好 可以用各种语言实现 界面可以做得很好看 做成pwa形式,界面看起来也可以很像原生程序 java gui 可以跨平台 java 也不是不可以,但总是要带着 jvm autoit 也可以,但不能跨平台 其它的 要么太冷门(Lazarus) 要么过时了(hta) 要么实现起来很困难(mfc winforms wpf) -->
因为要经常部署和重装系统,所以就整理了这样一句命令,可能会因为 docker 的更新而失效,要注意修命令里的版本号
如果一直安装失败,可以先设置好代理,再安装 docker
具体环境
这是文档 https://docs.docker.com/engine/install/debian/
sudo apt-get remove -y docker docker-engine docker.io containerd runc ; \
sudo apt-get update && \
sudo apt-get install -y \
ca-certificates \
curl \
gnupg \
lsb-release && \
if [ -e /usr/share/keyrings/docker-archive-keyring.gpg ] ; \
then rm /usr/share/keyrings/docker-archive-keyring.gpg; \
else curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg ;fi && \
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null && \
sudo apt-get update && \
sudo apt-get install -y docker-ce docker-ce-cli containerd.io && \
sudo docker run --rm hello-world && \
sudo curl -L --retry 100 --retry-delay 2 "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose && \
sudo chmod +x /usr/local/bin/docker-compose && \
docker-compose --version
如果 docker-compose 总是下载失败,可以尝试使用这样的脚本下载
COMMAND="curl -L https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose"
for ((i=0;i<100;i++))
do
$COMMAND
if [ $? -eq 0 ]; then
exit 0;
fi
done
sudo chmod +x /usr/local/bin/docker-compose
docker-compose --version
需要改的不是环境变量,而且是启动时的环境变量 https://docs.docker.com/engine/daemon/proxy/#environment-variables
在这个文件里 /etc/systemd/system/docker.service.d/http-proxy.conf 追加以下内容
[Service]
Environment="HTTP_PROXY=http://127.0.0.1:1081"
Environment="HTTPS_PROXY=http://127.0.0.1:1081"
Environment="NO_PROXY=localhost,127.0.0.1,.corp"
如果没有 http-proxy.conf 就自己新建一个
sudo mkdir -p /etc/systemd/system/docker.service.d
vim /etc/systemd/system/docker.service.d/http-proxy.conf
修改完后的重启
sudo systemctl daemon-reload
sudo systemctl restart docker
查看环境变量有没有设置成功
sudo systemctl show --property=Environment docker
docker info | grep -i proxy
查看 docker 的状态和日志,这个是用于观察 docker 是否有正确启动,配置文件有没有写错,如果启动失败有什么错误输出
systemctl status docker
journalctl -u docker.service
如果拉取镜像时遇到这种错误 TLS handshake timeout , 可以尝试修改 daemon.json 里的 mut , daemon.json 的路径可能是 /etc/docker/daemon.json 也可能是 ~/docker/daemon.json
{
...
"mtu": 1300
...
}
<!-- ,mirror.aliyuncs.com,daocloud.io,baidubce.com,dockerproxy.com,iscas.ac.cn,huecker.io,timeweb.cloud,noohub.ru ,mirror.aliyuncs.com,daocloud.io,baidubce.com,dockerproxy.com,iscas.ac.cn,huecker.io,timeweb.cloud,noohub.ru Environment="http_proxy=http://127.0.0.1:1081" Environment="HTTPS_PROXY=http://127.0.0.1:1081" Environment="ALL_PROXY=socks5h://127.0.0.1:1080" ~/docker/daemon.json cat /etc/docker/daemon.json vim /etc/docker/daemon.json tee /etc/docker/daemon.json <<EOF { "proxies" : { "http-proxy" : "http://127.0.0.1:1081", "no-proxy" : "localhost,127.0.0.0/8", "https-proxy" : "http://127.0.0.1:1081" } } EOF "mtu": 1300 { "proxies": { "http-proxy": "http://192.168.0.10:10809", "https-proxy": "http://192.168.0.10:10809", "no-proxy": "*.test.example.com,.example.org,127.0.0.0/8" } } Environment="http_proxy=http://127.0.0.1:1081" Environment="HTTPS_PROXY=http://127.0.0.1:1081" Environment="ALL_PROXY=socks5h://127.0.0.1:1080" ~/docker/daemon.json cat /etc/docker/daemon.json vim /etc/docker/daemon.json tee /etc/docker/daemon.json <<EOF { "proxies" : { "http-proxy" : "http://127.0.0.1:1081", "no-proxy" : "localhost,127.0.0.0/8", "https-proxy" : "http://127.0.0.1:1081" } } EOF "mtu": 1300 { "proxies": { "http-proxy": "http://192.168.0.10:10809", "https-proxy": "http://192.168.0.10:10809", "no-proxy": "*.test.example.com,.example.org,127.0.0.0/8" } } systemctl daemon-reload; systemctl restart docker; docker pull busybox -->
具体环境
docker pull debian:11
docker run \
-it \
--rm \
-p 443:443 \
debian:11 /bin/bash
cp /etc/apt/sources.list /etc/apt/sources.list_bak && \
sed -i 's/deb.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list && \
apt update && \
apt install -y vim && \
apt install -y curl && \
apt install -y net-tools && \
apt install -y netcat && \
apt install -y procps
apt install -y bsdmainutils
apt install -y python3
apt install -y python3-pip
例子
curl -C - -o php-7.3.11.tar.gz https://www.php.net/distributions/php-7.3.11.tar.gz
解释
-L 允许重定向
-C 开启断点续传
- 这个表示开始和结束位置,一般就这样就可以了
--retry 100 超时重试 100 次,也可以是断点续传时的重试
--retry-delay 5 每次超时后等待 5 秒再重试
--connect-timeout 5 连接超过 5 秒算超时
一次连接超时时间。如果出错, 提示形如:curl: (28) connect() timed out!
--max-time 10 单次请求的最大时间
一次连接过程最大的允许时间。出错提示如:curl: (28) Operation timed out after 2000 milliseconds with 0 bytes received
--max-time 要大于 --connect-timeouts
--retry-max-time 30 整体请求的最大时间
-o 参数将服务器的回应保存成文件
-O 参数将服务器回应保存成文件,并将 URL 的最后部分当作文件名。
如果服务器主动返回 失败 例如 reset 这类的,就会直接退出的了,不论有没有设置 --retry
curl 提供了一个脚本用于方便下载文件 https://github.com/curl/wcurl
github 好像不支持断点下载
curl 遇到这种错误会直接退出,--retry 这时是没有效果的 Connection reset by peer
alias ll="ls -l "alias ll="ls -l "alias
alias -p
删除一个别名
unalias ll
删除两个别名
unalias ll ll2
删除全部别名
unalias -a
判断 PS1 是不是环境变量
printenv|awk -F '=' ' {print $1}'|grep "^PS1$"
printenv|awk -F '=' ' {print $1}'|grep "^PS1$";if [ "$?" -eq 1 ]; then echo "1"; else echo "0"; fi;
printenv|awk -F '=' ' {print $1}'|grep "^PS1$";if [ "$?" -eq 1 ]; then echo "This variable is not an environment variable"; else echo "This variable is an environment variable"; fi;
printenv|awk -F '=' ' {print $1}'|grep "^PS1$" 1>/dev/null ;if [ "$?" -eq 1 ]; then echo "This variable is not an environment variable"; else echo "This variable is an environment variable"; fi;
<!-- ## 在 bash 里判断一个文件的类型 判断 ./index.html 是不是文本文件 file -b -i ./index.html | grep "^text" 1>/dev/null ;if [ "$?" -eq 1 ]; then echo "This file is not a text file"; else echo "This file is a text file"; fi; 应该可以通过 file 命令来区分 文本文件 和 二进制文件 file -b -i 文件路径 -b 不输出文件名 -i 输出文件对应的 MIME type 和 MIME encoding -L 根据软连接重定向 --mime-type 只输出 MIME type 只有输出的是 text 开头的是文本文件,其它都当作是二进制文件(并不是很严谨) 一次列出当前目录下全部的 .html 文件 file -i ./*.html file -b -L --mime-type /bin/mail -->
<!-- /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin alias 和 $PATH echo $PATH|awk 'BEGIN{RS=":"}{print $0}' printenv PATH|awk 'BEGIN{RS=":"}{print $0}' printenv PATH|awk 'BEGIN{RS=":"}{print $0}' realpath file -L -i /bin/mail file -L --mime-type /bin/mail file -b -L --mime-type /bin/mail alias -p -->
因为 github 的 pull 和 push 总是超时,所以写了两段脚本用于失败后的自动重试
#!/bin/bash
# ./git_help.sh pull
# ./git_help.sh push
GIT_COMMAND="git "
case $1 in
"push"|"pull")
GIT_COMMAND=$GIT_COMMAND$1
;;
*)
echo "only input push or pull";
exit 1;
;;
esac
for ((i=0;i<100;i++))
do
$GIT_COMMAND
if [ $? -eq 0 ]; then
exit 0;
fi
done
# ./git_help.ps1 pull
# ./git_help.ps1 push
param($a)
$GIT_COMMAND = "git "
if ($a -eq "push") {
$GIT_COMMAND = $GIT_COMMAND + $a
} elseif ($a -eq "pull") {
$GIT_COMMAND = $GIT_COMMAND + $a
} else {
echo "only input push or pull"
exit 1
}
for ($i = 1; $i -lt 100; $i++) {
echo $i" "$GIT_COMMAND
PowerShell -command $GIT_COMMAND
# Invoke-Expression $GIT_COMMAND
# Invoke-Command -ScriptBlock {Write-Host $GIT_COMMAND}
# Invoke-Command -ScriptBlock {$GIT_COMMAND}
if ($? -eq $true) {
break
}
}
href 是 Hypertext Reference (超文本引用) 的缩写。 href 目的是为了建立联系,让当前标签能够链接到目标地址。
src 是 source (来源) 的缩写。 指向的内容将会应用到文档中当前标签所在位置。 例如 img 和 script 的 src 属性。
href 和 src 的值通常是 url 但也可以不是 url 。 其中一个例子就是 img 标签的 src 可以直接放 base64 的值。
可以简单但不严谨地理解为 href 不会加载, src 会加载。 这样解释好象很有道理。 但 link 标签是用 href 的。 link 标签能加载 css 和 页面图标 还有 manifest 还有 预加载的 js 。
它们的全称
URL,URN,URC 都属于 URI 。 语法都是
URI = scheme ":" scheme-specific-part
URI = scheme ":" ["//" authority] path ["?" query] ["#" fragment]
authority = [userinfo "@"] host [":" port]
一些例子
userinfo host port
┌──┴───┐ ┌──────┴──────┐ ┌┴┐
https://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top
└─┬─┘ └───────────┬──────────────┘└───────┬───────┘ └───────────┬─────────────┘ └┬┘
scheme authority path query fragment
ldap://[2001:db8::7]/c=GB?objectClass?one
└┬─┘ └─────┬─────┘└─┬─┘ └──────┬──────┘
scheme authority path query
mailto:John.Doe@example.com
└─┬──┘ └────┬─────────────┘
scheme path
news:comp.infosystems.www.servers.unix
└┬─┘ └─────────────┬─────────────────┘
scheme path
tel:+1-816-555-1212
└┬┘ └──────┬──────┘
scheme path
telnet://192.0.2.16:80/
└─┬──┘ └─────┬─────┘│
scheme authority path
urn:oasis:names:specification:docbook:dtd:xml:4.1.2
└┬┘ └──────────────────────┬──────────────────────┘
scheme path
URN 的作用是描述资源的身份,例如 一个人的名字。 URN 的其中一个应用例子是 图书的 ISBN 号码 。
URN 的语法
urn:NID:NSS
NID 是 namespace identifier (命名空间标识符) 的缩写。
NSS 是 namespace specific string (命名空间特定字符串) 的缩写。
URN 的 NID 和 NSS 部分相当于 URI 里的 path 部分。
URL 的作用是描述资源的访问路径,例如 一个人的住址。
URL 的语法
hierarchical part
┌───────────────────┴─────────────────────┐
authority path
┌───────────────┴───────────────┐┌───┴────┐
abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
└┬┘ └───────┬───────┘ └────┬────┘ └┬┘ └─────────┬─────────┘ └──┬──┘
scheme user information host port query fragment
URC (统一资源特征),在九十年代的时候, URL URI URC 被期望能组成一个互联网信息架构。 但 URC 一直停留在理论阶段,随之更晚出现的其他技术(例如 资源描述框架)取代了它们。
URI 的 scheme 和 URN 的 NID 都需要在 IANA 注册。
完整的 url 或 urn 会被称为绝对 uri , 只有一部分的 url 或 urn 会被称为相对 uri 。
还有一个 Data URI 或者叫做 Data URL 。 这是具体的语法,也属于 URI 。
dataurl := "data:" [ mediatype ] [ ";base64" ] "," data
mediatype := [ type "/" subtype ] *( ";" parameter )
data := *urlchar
parameter := attribute "=" value
比较好区分的一个特征是,以 urn 开头的 uri 就一定是 urn , 以 data 开头的 uri 就一定是 data url 。 除此之外的都是 url 。
url 两个斜杆 // 其实是没什么作用的
为什么文件 URL 以3斜杠开头?
curl -i -v file:///C:/Users/example.txt
curl -i -v file://localhost/C:/Users/example.txt
<!-- RFC1738 RFC8089 -->
<!-- host name = 主机名 domain name = 域名 FQDN Fully Qualified Domain Name 完全 合规 域 名 PQDN Partially Qualified Domain Name 部分 合规 域 名 FQDN = 主机名 + 域名 主机名可以命名为“部分合格的域名”。 因为主机名不提供域名。 我们只有知道或自动将域名添加到主机名时才能使用主机名。 例如,如果我们在同一个域中,则可以使用PQDN进行通信和规范。 域名的一种,能指定其在域名系统 (DNS) 树状图下的一个确实位置 主机名 一些语境下是指 FQDN 一些语境下是指 FQDN 中 最左边 或 查询过程中最后的一部分 域名 一些语境下是指 FQDN 一些语境下是指 FQDN 中除去 主机名 的部分 FQDN 中 最左边 或 查询过程中最后的一部分 有时也会被称为 服务名 主机名就机器本身的名字,域名是用来解析到IP的 -->
<!-- 1. 通电 1. 运行主板 ROM 里面的 BIOS 1. BIOS 加电自检 (POST, Power-On Self-Test) ,就是检查硬件 1. BIOS 根据指定的顺序,读取 MBR 中的引导程序(bootloader) 1. 启动 MBR 中的 GRUB ( linux 通常用 GRUB 作为引导程序) 1. GRUB 把 linux 内核加载到内存并把控制交给内核 1. 内核内存中自解压之后就将控制权交给 init 进程 - init 进程 通常是 systemd 或 init(SysV init) - 大多数 linux 发行版选择了 systemd 大致是 bios 内核引导 init getty login shell -->
现在主流的启动过程是
MBR -> GRUB -> initramfs -> systemd
简单但又不严谨地理解, init 是第一个运行在用户态的进程。 这里描述的 init 可能是 SystemV init 也可能是 UpStart 也可能是 systemd 。
笔者认为作为一个写上层应用的程序员,了解到 加载和启动 linux 内核镜像 这一层就已经足够深入的了。
# 获取本机公网 IP
curl ifconfig.me
curl icanhazip.com
curl ipinfo.io/ip
curl ipecho.net/plain
curl www.trackip.net/i
curl ip.sb
curl whatismyip.akamai.com
curl ifconfig.co
curl ident.me
curl inet-ip.info
curl 'https://api.ipify.org?format=json' #ipv4
curl 'https://api64.ipify.org?format=json' #ipv6
# 获取本机公网 IP ,这几个有返回位置信息
curl myip.ipip.net
curl ip.cn
curl cip.cc
curl ip-api.com
curl ip-api.com/json
# 查询某个ip的信息
curl http://ip-api.com/json/58.62.220.66
大概就两种套路,从标准输入读取代码,从命令行参数读取代码,从命令行参数读取代码时要留意转义字符
代码开头都不需要 <? 或 <?php
phpcode=$(cat <<- 'EOF'
echo '123';
echo "asd";
$a="qwe";
echo $a;
echo "\"\$a\"\\";
var_dump($argv);
EOF
);
echo $phpcode | php -a -- a=1;
php -r "$phpcode" -- a=1;
php -a <<- 'EOF' -- a=1;
echo '123';
echo "asd";
$a="qwe";
echo $a;
echo "\"\$a\"\\";
var_dump($argv);
EOF
nodecode=$(cat <<- 'EOF'
console.log('hello');
EOF
);
echo $nodecode | node
node -e "$nodecode"
node <<- 'EOF'
console.log('hello');
EOF
执行标准输入里的代码,和普通文件里的代码一样,必须要有换行符
pythoncode=$(cat <<- 'EOF'
print('hi1')
print('hi2')
EOF
);
echo $pythoncode | python
python << 'EOF'
print('hi1')
print('hi2')
EOF
在一行里,换行用分号;替代
python -c "import os;print(os.environ['PATH'])"
伪代码
totalPage = ceil((totalRecord + pageSize - 1) / pageSize);
php
$totalPage = ceil(($totalRecord + $pageSize - 1) / $pageSize);
sql
SELECT @totalRecord := 123, @pageSize := 6;
SELECT ceil((@totalRecord + @pageSize + 1) / @pageSize);
ceil 是 向上取整 的函数
关于分页的语法
SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset
三种写法
SELECT * FROM table LIMIT rows
SELECT * FROM table LIMIT offset, rows
SELECT * FROM table LIMIT rows OFFSET offset
具体的例子
-- 每页 10 行,第 1 页
SELECT * FROM table LIMIT 10
SELECT * FROM table LIMIT 0, 10
SELECT * FROM table LIMIT 10 OFFSET 0
-- 每页 10 行,第 2 页
SELECT * FROM table LIMIT 10, 10
SELECT * FROM table LIMIT 10 OFFSET 10
-- 每页 10 行,第 3 页
SELECT * FROM table LIMIT 20, 10
SELECT * FROM table LIMIT 10 OFFSET 20
-- 每页 10 行,第 4 页
SELECT * FROM table LIMIT 30, 10
SELECT * FROM table LIMIT 10 OFFSET 30
这是获取总行数的 sql
SELECT count(*) FROM table LIMIT 1;
这是获取总页数的 sql
SELECT @pageSize := 6;
SELECT ceil((count(*) + @pageSize + 1) / @pageSize) FROM table LIMIT 1;
SELECT ceil((count(*) + 7) / 6) from table LIMIT 1;
这是获取某一页的 sql
-- 每页 6 行,第 2 页
SELECT @pageSize := 6;
SELECT @pageNo := 2;
SELECT @rows := @pageSize;
SELECT @offset := (@pageNo-1)*@pageSize;
SELECT * FROM table LIMIT @offset, @rows;
SELECT * FROM table LIMIT @rows offset @offset;
计算当前页的行数,这是伪代码
function getCurrentPageSize(pageSize, pageNo, totalRecord, totalPage)
{
if (pageNo < totalPage) {
return pageSize;
} else if (pageNo == totalPage) {
return pageSize + (totalRecord - totalPage*pageSize);
} else {
// Throw an exception
}
}
apt install -y busybox
docker run -it --rm --name my-busybox busybox:1.36-glibc sh
type busybox
busybox --help
https://busybox.net/live_bbox/live_bbox.html
https://frippery.org/busybox/
https://github.com/rmyorston/busybox-w32
建议下载 busybox64u.exe 这个版本,64位且支持 unicode ,虽然这个版本只支持 win10和win11
直接用 apt 安装的 busybox 版本太旧了, busybox 常常要用到宿主机的文件,容器里的 busybox 用起来不怎么方便。
安装前置的依赖
apt install -y bzip2 && \
apt install -y make && \
apt install -y gcc
下载源码
curl -O "https://busybox.net/downloads/busybox-1.37.0.tar.bz2"
解压源码
tar -xjf ./busybox-1.37.0.tar.bz2
切换进源码目录并开始安装
cd busybox-1.37.0
make defconfig
make install
编译后的 可执行二进制文件 可能在当前编译的目录,可能在源码的目录,反正要找一下
find / -name busybox
找到后就复制或剪切到 /bin 目录
cp /root/busybox-1.37.0/busybox /bin/busybox
一句命令完成下载和安装,但需要是 root 用户,其它用户需要修改对应的目录
apt install -y bzip2 && \
apt install -y make && \
apt install -y gcc && \
cd && \
curl -L -O "https://busybox.net/downloads/busybox-1.37.0.tar.bz2" && \
tar -xjf ./busybox-1.37.0.tar.bz2 && \
cd busybox-1.37.0 && \
make defconfig && \
make install && \
cp /root/busybox-1.37.0/busybox /bin/busybox && \
cd
php -r 'phpinfo();' | grep 'Loaded Configuration File'
php -r 'echo php_ini_loaded_file();'
php --ini
php -i | grep 'Loaded Configuration File'
strace -f -e open,execve,openat php -v 2>&1 | grep "O_RDONLY) = 3"
cli fpm apache 的 php 配置文件可能会不一样。 fpm 还有一个单独的配置文件。 在 windows 环境下 strace 可能会有权限的问题,看不到输出。 cli 可以通过命令行比较准确地获得配置文件位置。 web 最保险的方式还是输出 php_ini_loaded_file() 函数。
使用这个仓库的代码来搭建 DNS , 使用这个仓库是因为笔者平时主要使用php做开发, https://github.com/yswery/PHP-DNS-SERVER
使用的是 v1.4.1 版本
git checkout v1.4.1
https://github.com/yswery/PHP-DNS-SERVER
composer install --no-suggest --no-dev --ignore-platform-reqs
require_once __DIR__.'/vendor/autoload.php';
$json = <<< EOF
{
"test.localhost.com": {
"A": "127.0.0.1"
}
}
EOF;
class JsonTextResolver extends \yswery\DNS\Resolver\JsonResolver
{
public function addZoneText(string $zone)
{
$zone = json_decode($zone, true);
$this->addZoneArr($zone);
}
public function addZoneArr(array $zone)
{
$resourceRecords = $this->isLegacyFormat($zone) ? $this->processLegacyZone($zone) : $this->processZone($zone);
$this->addZone($resourceRecords);
}
}
// JsonResolver created and provided with json dns records
$jsonResolver = new JsonTextResolver([]);
$jsonResolver->addZoneText($json);
// ipconfig /flushdns
// php localhost2.php
// System resolver acting as a fallback to the JsonResolver
$systemResolver = new yswery\DNS\Resolver\SystemResolver();
// StackableResolver will try each resolver in order and return the first match
$stackableResolver = new yswery\DNS\Resolver\StackableResolver([$jsonResolver, $systemResolver]);
// Create the eventDispatcher and add the event subscribers
$eventDispatcher = new \Symfony\Component\EventDispatcher\EventDispatcher();
$eventDispatcher->addSubscriber(new \yswery\DNS\Event\Subscriber\EchoLogger());
$eventDispatcher->addSubscriber(new \yswery\DNS\Event\Subscriber\ServerTerminator());
// Create a new instance of Server class
$config = null;
$storageDirectory = null;
$useFilesystem = false;
$ip = '127.0.0.1';
$port = 53;
$server = new yswery\DNS\Server($stackableResolver, $eventDispatcher, $config, $storageDirectory, $useFilesystem, $ip, $port);
// Start DNS server
$server->start();
<!-- $temp_file = tempnam(sys_get_temp_dir(), 'aaa'); \define('TEMP_RECORD_FILE', $temp_file); register_shutdown_function(function(){ if (is_file(TEMP_RECORD_FILE)) { unlink(TEMP_RECORD_FILE); } }); $json = <<< EOF { "shop-dev.theclub.com.hk": { "A": "127.0.0.1" } } EOF; file_put_contents(TEMP_RECORD_FILE, $json); // ipconfig /flushdns // php localhost.php // JsonResolver created and provided with path to file with json dns records $jsonResolver = new yswery\DNS\Resolver\JsonResolver([TEMP_RECORD_FILE]); -->
<!-- startup.bat startup.sh -->
php startup.php
<!-- 一般情况下 主DNS 访问失败时才会访问 备用DNS ,查询没有结果不算访问失败 -->
nslookup -debug -querytype=A -port=53 test.localhost.com 127.0.0.1
如何写配置文件可以参考仓库里的文档或参考 example 里的文件
如果不把设为服务,则每次开机后都要手工启动一次
笔者原本是想用php的库来建一个本地的dns服务,但找了很久都没找到合适的,最后还是选择用 unbound , 和 bind 相比, unbound 提供了免编译免安装的版本。
使用的是 v1.19.0 版本
https://github.com/NLnetLabs/unbound
https://unbound.docs.nlnetlabs.nl/en/latest/index.html
https://nlnetlabs.nl/projects/unbound/download/
cp example.conf unbound.conf
# 设置日志文件的路径,默认情况下会使用 syslog
logfile: unbound.log
use-syslog: no
interface: 127.0.0.1
local-data: "test.localhost.com A 127.0.0.1"
forward-zone:
name: "."
forward-addr: 系统原本的主dns地址
forward-addr: 系统原本的备用dns地址
unbound-checkconf unbound.conf
./unbound-checkconf.exe unbound.conf
# 在前台运行
unbound -vv -c unbound.conf
./unbound.exe -vv -c unbound.conf
# 在后台运行
unbound -d -vv -c unbound.conf
./unbound.exe -d -vv -c unbound.conf
<!-- unbound 如何设置 DNS-over-HTTPS? -->
通常是执行策略的原因导致的。
设置脚本执行策略,通常把 策略 设为 RemoteSigned 就可以了
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine
查看 powershell 脚本执行策略
Get-ExecutionPolicy
Get-ExecutionPolicy -List
https://docs.microsoft.com/zh-cn/powershell/module/microsoft.powershell.core/about/about_execution_policies?view=powershell-7.2
套一层 bat 脚本就可以直接执行 powershell 脚本了
@echo off
powershell -ExecutionPolicy Bypass -File "1.ps1" arg1 arg2 arg3
# powershell -ExecutionPolicy Bypass -File "1.ps1" arg1 arg2 arg3
Write-Host args_Count: $($args.Count) # 输出命令行参数的数量
Write-Host "$args" # 输出全部命令行参数
# powershell -ExecutionPolicy Bypass -File "2.ps1" -Param1 "Param1" -Param4 123
param([string]$Param1, [int]$Param2 = 2, $Param3 = 3, $Param4)
Write-Output "1: $Param1"
Write-Output "2: $Param2"
Write-Output "3: $Param3"
Write-Output "4: $Param4"
# 两种形式只能选择其中一种
```
$variable.GetType()
```
```
$variable | Get-Member
```
<!-- Add-Type -TypeDefinition https://learn.microsoft.com/zh-cn/powershell/module/microsoft.powershell.utility/add-type DllImport 和 LibraryImport 如果可能,在面向 .NET 7+ 时,请使用 [LibraryImport] 在某些情况下,使用 [DllImport] 是合适的 https://learn.microsoft.com/zh-cn/dotnet/standard/native-interop/pinvoke https://learn.microsoft.com/zh-cn/dotnet/standard/native-interop/best-practices https://learn.microsoft.com/zh-cn/dotnet/api/system.runtime.interopservices.dllimportattribute https://learn.microsoft.com/zh-cn/dotnet/standard/native-interop/abi-support 脚本(script) 函数(Functions) 模块(Module) cmdlet 程序集(Assembly) 这几个的区别? 脚本 函数 模块 都是 ps 代码 cmdlet 和 Assembly 则是编译后的 dll文件 (虽然理论上可以用其它语言(C++ VB F#),但绝大部分情况下都是 C#) cmdlet 只能用在 powershell 里 Assembly 可以用在其它 .net 程序里 如何区分一个类是 powershell 原本的类 还是 .NET 的类? 原本的类 就是 cmdlet https://learn.microsoft.com/zh-cn/powershell/module/microsoft.powershell.core/about/about_core_commands .NET 的类就是 GetType().FullName 返回值里没有 __ComObject 的 com 对象 (New-Object -ComObject WScript.Shell).GetType().FullName .NET 的类 (Get-Date).GetType().FullName 但 cmdlet 或 Assembly 都是可以自行增加的,也可以通过包管理工具怎加第三方的 如何通过字符串执行 powershell 命令? PowerShell -command $GIT_COMMAND Invoke-Expression $GIT_COMMAND 列出当前可用的 cmdlet Get-Command -CommandType Cmdlet 列出已加载的 Assembly [System.AppDomain]::CurrentDomain.GetAssemblies() 列出当前可以用的类,这里会输出超级多的类 [System.AppDomain]::CurrentDomain.GetAssemblies() | ForEach-Object { $_.GetTypes() } msdn 的文档虽然很丰富,但感觉很多概念依然很模糊 powershell 转换为 exe ps12exe https://github.com/steve02081504/ps12exe PS2EXE https://github.com/MScholtes/PS2EXE PowerShell脚本编译成EXE https://www.pstips.net/convert-ps1toexe.html 可以用 IExpress ,把脚本打包成一个自解压的文件 据说 PowerShell ISE 也可以直接把脚本转换成 exe ,但我的电脑的 ISE 却没有这个选项 PowerShell ISE 也不再积极开发了 https://learn.microsoft.com/zh-cn/powershell/scripting/windows-powershell/ise/introducing-the-windows-powershell-ise 新版的 powershell 通过这个 vsc 扩展提供支持 https://marketplace.visualstudio.com/items?itemName=ms-vscode.PowerShell -->
优点
缺点
php -r "copy('https://github.com/vrana/adminer/releases/download/v5.4.1/adminer-5.4.1.php', 'adminer.php');"
php -r "print((new SQLite3('test.db'))->querySingle('SELECT SQLITE_VERSION()'));"
mkdir adminer-plugins
touch login-password-less.php
vi login-password-less.php
<?php
/** Enable login without password
* @link https://www.adminer.org/plugins/#use
* @author Jakub Vrana, https://www.vrana.cz/
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @license https://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2 (one or other)
*/
class AdminerLoginPasswordLess extends Adminer\Plugin {
protected $password_hash;
/** Set allowed password
* @param string $password_hash result of password_hash()
*/
function __construct($password_hash) {
$this->password_hash = $password_hash;
}
function credentials() {
$password = Adminer\get_password();
return array(Adminer\SERVER, $_GET["username"], (password_verify($password, $this->password_hash) ? "" : $password));
}
function login($login, $password) {
// if ($login == 'admin' && $password == '') {
// return true;
// } else {
// return false;
// }
if ($password != "") {
return true;
}
}
protected $translations = array(
'cs' => array('' => 'Povolí přihlášení bez hesla'),
'de' => array('' => 'Ermöglicht die Anmeldung ohne Passwort'),
'pl' => array('' => 'Włącz logowanie bez hasła'),
'ro' => array('' => 'Activați autentificarea fără parolă'),
'ja' => array('' => 'パスワードなしのログインを許可'),
);
}
touch adminer-plugins.php
vi adminer-plugins.php
<?php // adminer-plugins.php
return array(
// new AdminerLoginPasswordLess('$2y$07$Czp9G/aLi3AnaUqpvkF05OHO1LMizrAgMLvnaOdvQovHaRv28XDhG'),
new AdminerLoginPasswordLess(password_hash("PASSWORD", PASSWORD_DEFAULT)),
// You can specify all plugins here or just the ones needing configuration.
);
<!-- 四个工作空间 工作区(Workspace) 暂存区(Index/Stage) 本地仓库(Repository) 远程仓库(Remote) 分支 标签 查看状态 日志 贮藏(stash) 对比文件 配置 打包 githook 客户端hook 服务端hook git服务 -->
<?php
require 'vendor/autoload.php';
use Symfony\Component\RateLimiter\Storage\InMemoryStorage;
use Symfony\Component\RateLimiter\RateLimiterFactory;
use Symfony\Component\RateLimiter\Storage\StorageInterface;
// use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\RateLimiter\LimiterStateInterface;
class FileStorage implements StorageInterface
{
public function save(LimiterStateInterface $limiterState): void
{
file_put_contents($limiterState->getId(), serialize($limiterState));
}
public function fetch(string $limiterStateId): ?LimiterStateInterface
{
if (!file_exists($limiterStateId)) {
return null;
}
$limiterState = unserialize(file_get_contents($limiterStateId));
$expireAt = $this->getExpireAt($limiterState);
if (null !== $expireAt && $expireAt <= microtime(true)) {
$this->delete($limiterStateId);
return null;
} else if (null === $expireAt) {
$this->delete($limiterStateId);
return null;
}
return $limiterState;
}
public function delete(string $limiterStateId): void
{
if (!file_exists($limiterStateId)) {
return;
}
unlink($limiterStateId);
}
private function getExpireAt(LimiterStateInterface $limiterState): ?float
{
if (null !== ($expireSeconds = $limiterState->getExpirationTime())) {
return microtime(true) + $expireSeconds;
}
return null;
}
}
$factory = new RateLimiterFactory([
'id' => 'login',
'policy' => 'fixed_window',
'limit' => 20,
// 'rate' => ['interval' => '15 minutes'],
'interval' => '60 seconds',
], new FileStorage());
$limiter = $factory->create('id');
$rateLimit = $limiter->consume();
if (!$rateLimit->isAccepted()) {
// header('');
http_response_code(429);
echo 'Too Many Requests';
} else {
echo 'OK';
}
echo PHP_EOL;
try {
// var_dump(file_exists('login-id'));
// $limiterState = unserialize(file_get_contents('login-id'));
// var_dump(get_class($limiterState));
$limiterState = (new FileStorage())->fetch('login-id');
echo $limiterState->getId();
echo PHP_EOL;
echo $limiterState->getExpirationTime();
echo PHP_EOL;
} catch(\Throwable $e) {
echo $e->getMessage();
echo PHP_EOL;
}
exit(0);
/*
composer require symfony/rate-limiter:6.4
PHP_CLI_SERVER_WORKERS="10" php -S 0.0.0.0:8080
curl http://127.0.0.1:8080/ratelimiter.php
echo $(for i in $(seq 1 10); do echo curl -o /dev/null -s -w %{http_code}, http://127.0.0.1:8080/ratelimiter.php; echo ";";done ) | \
xargs -d ";" -n 1 -P 2 bash -c '$0' | \
sed 's/,/\n/g'
如何改用 redis 或其它存储?
这个组件在 Symfony 里是如何使用的?
*/
<!-- 查看硬盘容量 df -h du -hs $(ls -A) 修改 root 密码 sudo passwd 在 google cloud shell 中更新 docker sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin sudo cp /usr/local/bin/docker-compose /usr/local/bin/docker-compose-bak sudo rm /usr/local/bin/docker-compose sudo ln -s /usr/libexec/docker/cli-plugins/docker-compose /usr/local/bin/docker-compose 查看当前网桥网络 docker network ls 创建用户定义的网桥网络 docker network create my-net 删除用户定义的网桥网络 docker network rm my-net 连接容器与用户定义的网桥的连接 docker network connect my-net my-nginx 断开容器与用户定义的网桥的连接 docker network disconnect my-net my-nginx 查看网络的信息 docker network inspect setting_default docker pull mysql:8.0 docker pull phpmyadmin:5.2-apache docker pull wordpress:6.7-php8.1-apache docker pull php:7.4-apache docker run --name mysqld --restart always -d \ -e TZ="Asia/Shanghai" \ -e MYSQL_ROOT_PASSWORD="123456" \ -e MYSQL_DATABASE="wp" \ -v `pwd`/mysql-data:/var/lib/mysql \ mysql:8.0 docker run --name phpmyadmin -d \ -e PMA_HOST=mysqld \ -p 8081:80 \ phpmyadmin:5.2-apache docker run --name wordpress -d \ -e WORDPRESS_DB_HOST=mysqld \ -e WORDPRESS_DB_USER=root \ -e WORDPRESS_DB_PASSWORD=123456 \ -e WORDPRESS_DB_NAME=wp \ -p 8080:80 \ -v `pwd`/wordpress:/var/www/html \ wordpress:6.7-php8.1-apache docker exec -it wordpress /bin/bash docker-php-ext-install pdo pdo_mysql mysqli docker logs wordpress docker network connect my-net phpmyadmin docker network connect my-net mysqld docker network connect my-net wordpress -v /some/local/directory/config.user.inc.php:/etc/phpmyadmin/config.user.inc.php echo "SetEnv HTTPS on" >> .htaccess 在 wp-config.php 的开头加上这两句 define( 'WP_HOME', 'https://8080-cs-285386365050-default.cs-asia-east1-vger.cloudshell.dev' ); define( 'WP_SITEURL', 'https://8080-cs-285386365050-default.cs-asia-east1-vger.cloudshell.dev' ); $_SERVER['HTTP_HOST'] = '8080-cs-285386365050-default.cs-asia-east1-vger.cloudshell.dev'; $_SERVER['HTTP_PORT'] = '80'; 如果遇到不断重定向或重定向不正确的问题,可以尝试在这个位置打断点 wp-includes/pluggable.php wp_redirect print_r(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS)); exit; 下载 wordpress 源码,可以修改最后的版本号或直接用 latest https://wordpress.org/wordpress-6.8.2.tar.gz https://wordpress.org/latest.zip 完全通过命令行的方式安装 wordpress https://make.wordpress.org/cli/handbook/how-to/how-to-install/ https://developer.wordpress.org/cli/commands/config/create/ 下载 wp-cli 创建 config.php 文件 创建数据库 运行安装命令 在 cloud shell 里修改文件要注意文件的权限 如果没有权限,可以先用 sudo chown 用户名 文件路径 改好权限,再修改文件,改完文件后要记得改回原本的权限 在 cloud shell 重启后,镜像和容器都会消失 vscode里安装这两个插件 Extension Pack for Java Spring Boot Extension Pack maven 镜像里已经包含jdk了 docker pull maven:3.9-eclipse-temurin-17-alpine 这是对应的 jdk 镜像 eclipse-temurin:17-jdk-alpine docker run -it --rm --name my-maven-project -p 8080:8080 -v "$(pwd)":/usr/src/mymaven -w /usr/src/mymaven maven:3.9-eclipse-temurin-17-alpine mvn clean install alias mvn='docker run -it --rm --name my-maven-project -p 8080:8080 -v "$(pwd)":/usr/src/mymaven -w /usr/src/mymaven maven:3.9-eclipse-temurin-17-alpine mvn' 使用这种别名的 mvn 就无法连贯地执行 mvn 命令 https://start.spring.io/ 在这里选好 需要的组件,可以直接下载,也可以只复制 pom.xml 的内容 最好还是用下载的 zip文件 除了 pom.xml 还需要一些文件才能启动 springboot 如果springboot项目里没有代码,那么 pom.xml 里要加上这句 <configuration> <skip>true</skip> </configuration> 相对完整的例子 <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <skip>true</skip> </configuration> </plugin> </plugins> </build> 安装依赖 mvn clean install mvn clean install -X clean 清理项目构建目录 install 完成代码编译、测试、打包后,将生成的构建产物(如 JAR/WAR 文件)安装到本地 Maven 仓库 -X 是输出调试信息 运行这句之后会在 target 文件夹下生成一个 jar 文件 通过 jar 启动 java -jar target/exportSystem-0.0.1-SNAPSHOT.jar 使用指定端口号启动 java -jar target/exportSystem-0.0.1-SNAPSHOT.jar --server.port=8083 java -jar -Dserver.port=8083 target/exportSystem-0.0.1-SNAPSHOT.jar 启动 mvn spring-boot:run 最简单的 curl -o demo.zip https://start.spring.io/starter.zip \ -d type=maven-project \ -d language=java \ -d groupId=com.example \ -d artifactId=demo \ -d name=demo \ -d packageName=com.example.demo \ -d dependencies=web \ -d javaVersion=17 加上 jpa 依赖的 curl -o demo.zip https://start.spring.io/starter.zip \ -d type=maven-project \ -d language=java \ -d groupId=com.example \ -d artifactId=demo \ -d name=demo \ -d packageName=com.example.demo \ -d dependencies=web,data-jpa \ -d javaVersion=17 这种命令的依赖名可以通过 https://start.spring.io 的 share 获取,share 在 ... 那个按钮里 unzip demo.zip -d demo && cd demo 如果依赖里有 数据库 redis es 这类,要正确地填写好对应的配置,才能顺利启动 springboot demo/src/main/java/com/example/demo/HelloController.java package com.example.demo; import org.springframework.web.bind.annotation.*; @RestController public class HelloController { @GetMapping("/hello") public String hello(@RequestParam(defaultValue = "World") String name) { return "Hello, " + name + "!"; } } 还差很多东西 模板 认证和授权 会话管理 验证 orm 缓存 队列 命令行 全文搜索 邮件 日志 。。。。 下载源码 下载完后运行这句 git config core.filemode false 新建auth.json echo '{"github-oauth": {"github.com": "ghp_uvgdfgfwergwe"}}' | json_pp > auth.json 新建文件夹docker 新建文件 touch dockerfile-php 新建文件 touch docker-compose.yml 新建文件 touch magento-site.conf 新建文件 touch init.sh mkdir docker; \ cd docker; \ touch dockerfile-php; \ touch docker-compose.yml; \ touch magento-site.conf; \ touch init.sh; \ cd .. 构建镜像 安装 composer 依赖 composer install composer require swissup/module-search-mysql-legacy --prefer-source --ignore-platform-reqs 运行安装命令 php bin/magento deploy:mode:set developer 修改配置 php bin/magento module:enable Swissup_SearchMysqlLegacy Swissup_Core php bin/magento config:set catalog/search/engine 'lmysql' 不是apache环境就不用运行这句 echo "SetEnv HTTPS on" >> pub/.htaccess php bin/magento config:set web/secure/base_url https://cloudshell.dev/ php bin/magento config:set web/unsecure/base_url https://cloudshell.dev/ php bin/magento config:set admin/url/use_custom_path 0 php bin/magento config:set web/seo/use_rewrites 0 php bin/magento config:set web/cookie/cookie_domain cloudshell.dev php bin/magento config:show web/secure/base_url; php bin/magento config:show web/unsecure/base_url; php bin/magento config:show admin/url/use_custom_path; php bin/magento config:show web/seo/use_rewrites; php bin/magento config:show web/cookie/cookie_domain; 运行构建命令 rm -rf var/di/* var/generation/* var/cache/* var/page_cache/* var/view_preprocessed/* var/composer_home/cache/* var/tmp/* && \ rm -rf generated/code/* generated/metadata/* pub/static/* ; \ php bin/magento setup:upgrade; \ php bin/magento setup:di:compile; \ php bin/magento setup:static-content:deploy -f; \ php bin/magento indexer:reindex; \ php bin/magento cache:flush; \ chown root:root -R /var/www/html/var && chmod 777 -R /var/www/html/var; \ chown root:root -R /var/www/html/pub && chmod 777 -R /var/www/html/pub; 修改文件 app/code/Magento/Backend/App/Area/FrontNameResolver.php isHostBackend 后台不要404 app/code/Magento/Store/Model/BaseUrlChecker.php execute 前台不要302 lib/internal/Magento/Framework/App/Router/Base.php _checkShouldBeSecure 前台不要302, 这是只有cli server才需要改的,这是因为 cli server 无法通过环境变量来修改 $_SERVER ,其实只要 $_SERVER['HTTPS']=on 就不用改这句了 原来可以直接修改 $_SERVER['HTTPS']=on; 可以在 phpserver/router.php 里直接加上 $_SERVER['HTTPS']=on; php bin/magento varnish:vcl:generate --access-list phpapache --backend-host phpapache --backend-port 80 --export-version 6 --grace-period 300 --output-file default.vcl 虽然没有redis,但速度并不慢 docker run \ --name test1 \ -it \ --rm \ -w /root \ -v `pwd`:/root \ debian:12 /bin/bash docker exec -it test1 /bin/bash curl -L -o yourls-1.9.2.tar.gz https://github.com/YOURLS/YOURLS/archive/refs/tags/1.9.2.tar.gz curl -L -o yourls-1.7.2.tar.gz https://github.com/YOURLS/YOURLS/archive/refs/tags/1.7.2.tar.gz curl -L -o yourls-1.7.2.zip https://github.com/YOURLS/YOURLS/archive/refs/tags/1.7.2.zip tar -xzf yourls-1.9.2.tar.gz tar -xzf yourls-1.7.2.tar.gz tar --lzip -xf yourls-1.7.2.zip <?php // 获取请求路径并解析可能的查询参数 $requestUri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); $filePath = $_SERVER['DOCUMENT_ROOT'] . $requestUri; // 检查是否为真实文件或目录 if (!file_exists($filePath) || is_dir($filePath)) { // 非真实文件/目录,交由 yourls-loader.php 处理 require __DIR__ . '/yourls-loader.php'; } else { return false; $extension = strtolower(pathinfo($filePath, PATHINFO_EXTENSION)); if ($extension == 'php') { require $filePath; exit; } else { return false; } } // 直接输出静态文件内容 $mimeType = mime_content_type($filePath); $extension = strtolower(pathinfo($filePath, PATHINFO_EXTENSION)); if ($extension == 'php') { require $filePath; exit; } else if ($extension == 'js') { $mimeType = 'application/javascript'; } else if ($extension == 'css') { $mimeType = 'text/css'; } // if ($mimeType == 'text/x-php') { // require $filePath; // exit; // } header("Content-Type: {$mimeType}"); readfile($filePath); exit; PHP_CLI_SERVER_WORKERS="10" php -S 127.0.0.1:80 router.php docker pull yourls:1.9.2-apache docker run --name some-yourls \ -e YOURLS_SITE="https://example.com" \ -e YOURLS_USER="example_username" \ -e YOURLS_PASS="example_password" \ -e YOURLS_DB_HOST=10.1.2.3:3306 \ -e YOURLS_DB_USER= \ -e YOURLS_DB_PASS= \ -d yourls:1.9.2-apache 在 centos7.6 安装 apache2.4.6 和 php8.1 docker run \ --name test1 \ -it \ --rm \ centos:7.6.1810 /bin/sh 更换yum源 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo yum -y update 安装一些必要的依赖 yum install -y gcc gcc-c++ make autoconf automake pkg-config export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig/ pkg-config --variable pc_path pkg-config curl -L -O http://download.libsodium.org/libsodium/releases/libsodium-1.0.18-stable.tar.gz tar -xzf libsodium-1.0.18-stable.tar.gz cd libsodium-stable ./configure --prefix=/usr/local/libsodium make && make check make install cp /usr/local/libsodium/lib/pkgconfig/libsodium.pc /usr/share/pkgconfig/libsodium.pc /usr/share/pkgconfig 这个路径是通过这个命令找到的 pkg-config --variable pc_path pkg-config 用这个命令来检查 libsodium 有没有顺利地安装 pkg-config --modversion libsodium 安装 apache2.4.6 yum install -y httpd-2.4.6 httpd-devel 安装 php8.1 需要的依赖 yum install -y libxml2-dev yum install -y openssl-devel yum install -y sqlite-devel yum install -y bzip2-devel yum install -y gmp-devel yum install -y libicu-devel yum install -y http://down.24kplus.com/linux/oniguruma/oniguruma-devel-6.7.0-1.el7.x86_64.rpm yum install -y http://down.24kplus.com/linux/oniguruma/oniguruma-6.7.0-1.el7.x86_64.rpm yum install -y readline-devel yum install -y libxslt-devel yum install -y curl curl-devel php的mbstring的正则表达式功能需要oniguruma 安装php8.1 curl -L -O https://www.php.net/distributions/php-8.1.32.tar.gz tar -xzf php-8.1.32.tar.gz cd php-8.1.32 ./configure \ --prefix=/usr/local/php \ --with-config-file-path=/usr/local/php \ --enable-bcmath \ --with-curl \ --enable-mbstring \ --with-mysqli \ --with-pdo-mysql \ --with-openssl \ --enable-sockets \ --enable-soap \ --enable-intl \ --with-zlib \ --enable-opcache \ --with-bz2 \ --enable-pcntl \ --enable-sysvsem \ --enable-sysvshm \ --enable-sysvmsg \ --with-iconv \ --with-readline \ --with-pdo-sqlite \ --with-sqlite3 \ --with-xsl \ --enable-shmop \ --with-gettext \ --with-gmp \ --with-sodium \ --with-apxs2=/usr/bin/apxs make && make test make install cp php.ini-development /usr/local/php/php.ini sed -i "s/;zend_extension=opcache/zend_extension=opcache/" /usr/local/php/php.ini 这四个命令通常用于编译和安装软件,尤其是在使用 `Makefile` 的项目中。它们的区别和连携如下: 1. **configure**: - 这个命令通常用于准备软件的构建环境。它会检查系统的环境和依赖项,生成适合当前系统的 `Makefile`。在执行 `configure` 时,用户可以指定一些选项来定制构建过程,比如安装路径、启用或禁用某些功能等。 2. **make**: - 这个命令会根据 `Makefile` 中的指令编译源代码。它会调用编译器(如 `gcc`)来生成可执行文件或库。`make` 会自动处理文件之间的依赖关系,只重新编译那些自上次编译以来发生变化的文件。 3. **make test**: - 这个命令通常用于运行项目的测试套件。它会执行在 `Makefile` 中定义的测试目标,确保软件在安装之前能够正常工作。并不是所有的项目都有这个目标,具体取决于开发者是否在 `Makefile` 中定义了测试相关的规则。 4. **make install**: - 这个命令会将编译好的程序和相关文件复制到系统的指定位置(通常是 `/usr/local/bin`、`/usr/local/lib` 等)。这个步骤通常需要管理员权限,因为它涉及到对系统目录的写入。 ### 关系: - 通常的工作流程是先运行 `configure`,然后运行 `make` 来编译代码,接着可以选择运行 `make test` 来验证编译结果,最后使用 `make install` 将软件安装到系统中。 - 这些命令的执行顺序是有意义的,确保在安装之前软件是经过编译和测试的,从而减少安装后出现问题的可能性。 chown root:root -R /root/YOURLS-1.9.2 && chmod 777 -R /root/YOURLS-1.9.2; chown root:root -R /root && chmod 777 -R /root; sudo chown www-data:www-data -R /root/m2 && sudo chmod 777 -R /root/m2; --enable-cli 和 --enable-cgi 同时默认有效 --disable-cgi 没有这个编译参数,就能生成 php-cgi 编译php需要加上--enable-fpm这个参数才会有php-fpm 编译php需要加上 --with-apxs2=/usr/bin/apxs 才会有 apache 的模块 寻找 apxs 的路径 find / -name apxs apxs 是通过 httpd-devel 安装的 docker run --name test1 -it --add-host="host.docker.internal:host-gateway" --rm -w /root -v `pwd`:/root debian:12 /bin/bash --add-host="host.docker.internal:host-gateway" 加上这一句确实可以 通过 host.docker.internal 访问宿主机,但宿主机的服务必须是绑定 0.0.0.0 这个地址 文件管理 https://github.com/prasathmani/tinyfilemanager git clone -b 2.6 --single-branch --no-tags https://github.com/prasathmani/tinyfilemanager.git --depth=1 tinyfilemanager 终端 https://github.com/tsl0922/ttyd vscode 一个统一的页面 docker run \ --name test1 \ -it \ --rm \ -w /root \ -v `pwd`:/root \ -p 8080:8080 \ --add-host="host.docker.internal:host-gateway" \ debian:12 /bin/bash sudo apt-get update sudo apt-get install -y build-essential cmake git libjson-c-dev libwebsockets-dev git clone https://github.com/tsl0922/ttyd.git cd ttyd && mkdir build && cd build cmake .. make && sudo make install ttyd --writable -c admin:passwd -p 8080 bash mypanel git clone https://github.com/mypanel/mypanel.git --depth=1 mypanel ./init.sh dockerfile-php-apache 服务器管理面板的功能 应用商店 查看系统状态 定时任务 systemd 脚本管理 文件管理 docker 警报 webhook 进程 当前进程 守护进程 防火墙 waf ftp 邮局 网站 数据库 日志 面板日志 ssh登录日志 网站日志 系统日志 设置 就是要把命令行变成可视化的界面 安装要方便, 依赖要少, 最好能兼容多种系统 先修改 root 密码 sudo passwd 再切换到 root 用户 su root 再切换到 root 根目录 cd docker run -d -e OLLAMA_ORIGINS="*" -v ollama:/root/.ollama -p 11434:11434 --name ollama ollama/ollama docker exec -it ollama ollama run llama3.2 OLLAMA_ORIGINS="*" 设置这个环境变量是为了避免跨域限制,这是不安全的 在 Mac 上,可以通过运行以下命令找到日志: cat ~/.ollama/logs/server.log 在 Linux 系统中使用 systemd 时,可以使用以下命令查找日志: journalctl -u ollama --no-pager 当你在 容器 中运行 Ollama 时,日志会输出到容器的 stdout/stderr: docker logs <container-name> 拉取模型 curl http://localhost:11434/api/pull -d '{ "model": "deepseek-r1:1.5b" }' curl http://localhost:11434/api/pull -d '{ "model": "phi4-mini:3.8b" }' phi4-mini:3.8b deepseek-r1:7b deepseek-r1:8b 删除模型 curl -X DELETE http://localhost:11434/api/delete -d '{ "model": "deepseek-r1:7b" }' 模型列表 curl http://localhost:11434/api/tags 模型详细信息 curl http://localhost:11434/api/show -d '{ "model": "deepseek-r1:1.5b" }' 当前运行的模型 curl http://localhost:11434/api/ps curl http://localhost:11434/api/generate -d '{ "model": "deepseek-r1:1.5b", "prompt":"Why is the sky blue?", "stream": false }' curl http://localhost:11434/api/chat -d '{ "model": "deepseek-r1:1.5b", "messages": [ { "role": "user", "content": "why is the sky blue?" } ], "stream": false }' ollama 的 api 大致分为两种 completion 和 chat completion 两个接口的参数大致相同 completion 用的是 prompt chat completion 用的是 messages "messages": [ {"role":"system", "content":""}, {"role":"user", "content":""}, {"role":"assistant", "content":""}, ] role 区别 system 设定 AI 的行为,角色,背景 user 用户的输入 assistant ai 的输出 completion 也可以称为 text completion completion 是一次性的,生成长文本这类可以用 completion 多轮对话要用 chat completion 如果只有一轮对话 completion 和 chat completion 区别应该不大 completion 补全 docker run -d -p 8081:8080 -e OLLAMA_BASE_URL=http://localhost:11434 -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main docker run --rm -d -p 8081:4173 --name hollama ghcr.io/fmaclen/hollama:latest git clone https://github.com/ollama-ui/ollama-ui cd ollama-ui make download_resources python3 -m http.server --bind 127.0.0.1 8082 vi api.js , {credentials: 'include'} 安装不同版本的python 寻找可以安装的python yum list python* yum list python3* yum install python3.1* 安装新版python yum install python3.11 把新版python加入到 alternatives alternatives --install /usr/bin/python python /usr/bin/python3.11 1 配置默认python版本,这一步需要手动选择一个版本 alternatives --config python 显示默认python版本 alternatives --display python alternatives 是一个多版本管理工具,一般用在 CentOS/RHEL update-alternatives 和 alternatives 类似,命令也基本一样,一般用在 debian 在 CentOS/RHEL 中, update-alternatives 是 alternatives 的别名 alternatives 是一个 Linux 系统管理工具,主要用于管理同一命令的多个可执行文件版本(例如不同版本的 Java、Python等) 它通过符号链接机制实现,核心目标是解决 "多版本共存" 和 "命令路径冲突" 问题。 三层链接结构 第一层:用户调用标准路径(如 /usr/bin/java) 第二层:指向 /etc/alternatives/java(由工具管理的符号链接) 第三层:指向实际程序路径(如 /usr/lib/jvm/java-17-openjdk/bin/java) /usr/bin/java → /etc/alternatives/java → /usr/lib/jvm/java-17-openjdk/bin/java python的多文件编程 同级目录导入 文件名即是模块名 包结构组织导入 my_package/ ├── __init__.py ├── math_utils.py └── greetings.py 必须包含__init__.py文件(可为空) 作用是将一个文件夹变为一个Python模块 导入包的时候,实际上是导入了它的__init__.py文件 跨目录动态导入 使用sys.path.append()添加搜索路径 模块 (Module) 一个 .py 文件就是一个模块 包 (Package) 一个包含多个模块(和子包)的目录 python 中的框架(framework)和库(library)本质上是 包 python 的包本质上是 模块 import 模块[.模块]* [as 别名] from 模块[.模块]* import 成员 [as 别名] 成员 可以是模块 ,可以是模块中的类,可以是模块中的函数 Python会按照下面的路径列表顺序地查找我们需要的模块: 当前的工作目录; PYTHONPATH(环境变量)中的每一个目录; Python 默认的安装目录 虚拟环境路径 site-packages路径 动态引入的目录 sys.path.append sys.path 属性总是包含一个默认路径的列表 gitk 依赖 tk pacman -S 包名 pacman -Ss 搜索名称 pacmain -Q 列出所有已安装的包名 pacmain -Qi 列出所有已安装的包名,详细信息 宿主机 换源 update 安装必要的依赖 安装docker 安装梯子 docker设置代理 容器里 换源 update 安装必要的依赖 -->