PowerShell 环境变量设置:临时赋值、永久写入与路径追加
临时设置(当前会话有效) $env:ADMIN_PASSWORD = "your-password"关闭终端后失效。读取: echo $env:ADMIN_PASSWORD # 或 Write-Host $env:ADMIN_PASSWORD永久设置(当前用户) [System.Environment]::SetEnvironmentVariable("ADMIN_PASSWORD", "your-password", "User")写入注册表 HKCU\Environment,重新打开终端生效,不影响其他用户。 永久设置(系统级,需管理员权限) [System.Environment]::SetEnvironmentVariable("ADMIN_PASSWORD", "your-password", "Machine")写入 HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment,所有用户生效。 读取已保存的环境变量 # 读取用户级别 [System.Environment]::GetEnvironmentVariable("ADMIN_PASSWORD", "User")# 读取机器级别 [System.Environment]::GetEnvironmentVariable("ADMIN_PASSWORD", "Machine")删除环境变量 # 删除用户级别 [System.Environment]::SetEnvironmentVariable("ADMIN_PASSWORD", $null, "User")追加 PATH(避免覆盖) $current = [System.Environment]::GetEnvironmentVariable("PATH", "User") [System.Environment]::SetEnvironmentVariable("PATH", "$current;D:\my-tools", "User")不要直接给 PATH 赋值,否则会覆盖已有路径。 当前会话立即生效 SetEnvironmentVariable 修改的是注册表,当前会话的 $env: 不会自动更新。如果需要立即生效,手动同步一次: $env:ADMIN_PASSWORD = [System.Environment]::GetEnvironmentVariable("ADMIN_PASSWORD", "User")查看所有环境变量 Get-ChildItem Env:
PowerShell 设置环境变量:临时、当前用户、系统级
PowerShell 里改环境变量有三档:当前会话、当前用户永久、系统级永久,权限和作用范围各不相同。搞混了一堆脚本会失效。 临时(仅当前 PowerShell 窗口) $env:MY_TOKEN = "secret" echo $env:MY_TOKEN只影响当前会话 关掉窗口就没了 90% 的临时脚本调试用这个就够对子进程也生效: $env:PYTHONPATH = "D:\repo\src" python main.py # main.py 里能读到永久(当前用户) [System.Environment]::SetEnvironmentVariable("MY_TOKEN", "secret", "User")写到注册表 HKCU\Environment 新开的进程能读到 当前 PowerShell 窗口需要重开 才能通过 $env:MY_TOKEN 看到不重开也想立刻用的话: $env:MY_TOKEN = "secret" # 先本地设一份永久(系统级) 需要管理员 PowerShell: [System.Environment]::SetEnvironmentVariable("MY_TOKEN", "secret", "Machine")写到 HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment 所有用户都能读到 用于系统服务、多用户共享配置读取和删除 读: $env:MY_TOKEN [System.Environment]::GetEnvironmentVariable("MY_TOKEN", "User") [System.Environment]::GetEnvironmentVariable("MY_TOKEN", "Machine")删(把值设为空字符串就是删除): [System.Environment]::SetEnvironmentVariable("MY_TOKEN", $null, "User")追加到 PATH 写 PATH 一定要先读旧的再拼,不然会把系统原本的 PATH 覆盖掉: $old = [System.Environment]::GetEnvironmentVariable("Path", "User") $new = "$old;C:\Users\me\bin" [System.Environment]::SetEnvironmentVariable("Path", $new, "User")去重和验证: $new.Split(";") | Sort-Object -Unique三档对比目标 写法 生效范围只当前窗口 $env:X = "v" 当前会话 + 子进程当前用户永久 [Environment]::SetEnvironmentVariable("X","v","User") 新开进程,用户级系统级永久(管理员) [Environment]::SetEnvironmentVariable("X","v","Machine") 新开进程,所有用户老 Windows API:setx 老一辈 Windows 用 setx: setx MY_TOKEN secret # 用户 setx MY_TOKEN secret /M # 系统(管理员)坑:有 1024 字符限制,PATH 老长了会被截断 也不影响当前窗口一般还是推荐 [Environment]::SetEnvironmentVariable。 一句话总结 会话内 $env:X;永久用 [Environment]::SetEnvironmentVariable,第三参数 "User" 或 "Machine" 决定作用域。改 PATH 记得先读再拼。
IBM Db2 的定位与应用领域
IBM Db2 是 IBM 的大型关系型数据库,在互联网公司几乎看不到,但在金融、政府和大型机生态中至今仍是核心基础设施。 核心应用领域 银行 / 金融(最主要场景) Db2 在这个领域的地位最为稳固:银行核心账务系统 信贷审批和清算 证券交易撮合 保险核心系统原因是 Db2 在 IBM 大型机(z/OS)上的 ACID 事务能力经过几十年验证,部分银行核心系统已稳定运行 20~30 年,日均处理数亿笔交易几乎不宕机。很多老牌银行的底层组合是 IBM Mainframe + z/OS + Db2,更换成本极高。 政府 / 大型国企 历史上大量政府和国企采购了 IBM 的全套方案(小型机 + AIX + WebSphere + Db2),典型领域:税务系统 社保和医保系统 电信计费 能源调度 铁路订票这类系统生命周期很长,更倾向于稳定性而非新技术,因此沿用至今。 大型机(Mainframe)生态 这是 Db2 最特殊的优势——大多数开发者接触不到 IBM 大型机,但全球大量关键基础设施仍在 Mainframe 上运行:全球 80% 以上的信用卡交易、几乎所有主要航空公司的订票系统、大量跨国银行的清算网络。Db2 在这个生态里几乎是"官方搭档"。 ERP / 企业系统 传统 Java EE 企业项目的经典组合:WebSphere + Db2 + Oracle,在财务、供应链、仓储管理类系统中有相当存量。 为什么互联网公司很少用 互联网公司的优先考量是:开源:避免商业授权成本 社区活跃:遇到问题能快速找到解决方案 云原生:与 Kubernetes、微服务架构配合 弹性伸缩:流量波动大,需要横向扩展Db2 的定价体系较重,运维门槛高,人才市场小,不符合互联网团队的需求。 与 MySQL / PostgreSQL 的定位差异维度 Db2 MySQL / PostgreSQL授权模式 商业授权 开源主要场景 传统企业、大型机 互联网、云原生运维成本 高 低事务处理 极强 强大型机支持 原生 无新项目采用率 低 高现实价值 虽然新项目几乎不选 Db2,但现有存量系统的价值不可忽视:每天处理几亿笔交易、稳定运行 20+ 年、几乎零宕机的系统,才是传统金融机构最看重的能力。Db2 DBA 在银行/证券/保险行业仍是稀缺岗位。
读懂 webpack 混淆代码:(0, fn)() 模式与 RxJS 链解析
(0, fn)(...) 是什么 这是 webpack / Babel 生成代码中常见的间接调用写法: (0, s.p)(args)等价于: const _fn = s.p; _fn(args); // 普通函数调用,this === undefined(严格模式)为什么不直接 s.p(args)? s.p(args) 会将 this 绑定为 s;逗号运算符写法 (0, s.p) 会把方法"脱离"对象,变成普通函数调用,this 不再指向 s。 这在以下场景有实际意义:s.p 是从模块导入的函数(如 rxjs.from),不应绑 this 打包工具为了兼容 ES Modules 的 strict mode 语义,确保 this === undefined Tree-shaking 友好:逗号写法对某些打包器更易分析常见形式: (0, rxjs.of)(1, 2, 3) // 等价 rxjs.of(1, 2, 3) (0, lodash.map)(arr, fn) // 等价 lodash.map(arr, fn) (0, react.createElement)(...) // 等价 react.createElement(...) (0, o.Z)(list) // 混淆后的模块导出函数读到这种代码,直接把 (0, expr) 去掉,剩下的 expr(...) 就是实际调用。 真实打包代码示例 下面是一段典型的混淆打包代码(来自实际页面逆向): (0, s.p)( (t = window.$).when.apply(t, (0, o.Z)(window.beforeSubmitQueue.map(function(e) { return e(); })) ) ).switchMap( window.MarkLib.submitMarkAnswer.bind(window.MarkLib, !0, e) ).filter(function(t) { var n = t.fire_status, r = void 0 === n || n; var a = t.reject, o = void 0 !== a && a; return !e && w(!1), r && !o; }).map(JSON.stringify.bind(JSON)).do(function(t) { return y({ type: "markpage/saveAnswer", payload: { isTemporary: 1, packetId: Number(p), ... } }); }).subscribe();逐步还原 第一步:去掉 (0, expr) 包装 s.p(...) // s.p 可能是 rxjs.from / rxjs.fromPromise o.Z(list) // o.Z 是某个导出函数,根据上下文判断第二步:提取 window 上的对象引用 const { $, beforeSubmitQueue, MarkLib } = window;第三步:还原 .apply 和 .bind // (t = window.$).when.apply(t, args) → $.when(...args) // fn.bind(obj, true, e) → () => obj.fn(true, e)第四步:改写旧版 RxJS API旧版 新版.do(fn) .tap(fn)fromPromise(p) from(p).map(fn) .map(fn) 不变还原结果: const { $, beforeSubmitQueue, MarkLib } = window;from($.when(...beforeSubmitQueue.map(fn => fn()))) .pipe( switchMap(() => MarkLib.submitMarkAnswer(true, e)), filter(({ fire_status = true, reject = false }) => { if (!e) w(false); return fire_status && !reject; }), map(JSON.stringify), tap(answer => { y({ type: "markpage/saveAnswer", payload: { isTemporary: 1, packetId: Number(p), pageId: Number(a), round: f, stage: k, answer: j(answer, c, u) }, callback() { if (!e) w(false); } }); }) ) .subscribe();逻辑说明 还原后的业务逻辑只有一句话:执行提交前钩子(beforeSubmitQueue)→ 提交答案(submitMarkAnswer)→ 过滤无效结果 → 序列化 → 保存到 Redux store关键点:$.when(...tasks):jQuery Deferred,等待所有 before-hooks 完成 switchMap:前一个 Observable 完成后切换到新的,丢弃之前未完成的 filter:fire_status 不为 false 且 reject 不为 true 才继续 .subscribe():没有 subscribe,RxJS 链不会执行(冷 Observable)其他常见混淆模式 // void 0 === undefined void 0 // → undefined// !! 转布尔 !!value // → Boolean(value)// 逗号运算符返回最后一个值 (a(), b(), c()) // 执行 a、b、c,返回 c 的值// 短路赋值 x = void 0 === x ? defaultVal : x // → x ?? defaultVal(现代写法)读打包代码时,把这些模式认出来后,理解代码逻辑会快很多。
Windows 报 WinError 206 路径太长?三种彻底解法
Python 里跑数据集处理,Windows 突然崩: FileNotFoundError: [WinError 206] 文件名或扩展名太长。: 'cache\\vendor\\dataset_2026\\...\\CAM_FRONT_WIDE_H110_HR\\virtual_image'不是数据太大,是这个路径字符串太长——超过了 Windows 老古董的 MAX_PATH = 260 限制。分批读取、分段处理、分次遍历都没用,open() 那一刻就已经炸了。 方案一:开注册表长路径支持(一次性) Windows 10/11 内核其实支持长路径,但默认关着。管理员 PowerShell: New-ItemProperty ` -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" ` -Name "LongPathsEnabled" ` -Value 1 ` -PropertyType DWORD ` -Force或 CMD: reg add HKLM\SYSTEM\CurrentControlSet\Control\FileSystem ^ /v LongPathsEnabled /t REG_DWORD /d 1 /f重启电脑,或者至少重启 Python / IDE 让新进程读到设置。 注意:仅这一步对某些老 Python API、部分 C 扩展、zipfile、shutil 不一定生效——它们内部还在走 260 限制的老 API。 方案二:\\?\ 前缀(最稳) Windows 内核 API 支持超长路径,但要显式加 \\?\ 前缀: import osdef win_long_path(path: str) -> str: """把路径转成支持超长的形式""" p = os.path.abspath(path) if not p.startswith("\\\\?\\"): p = "\\\\?\\" + p return pwith open(win_long_path(long_path)) as f: ...关键点:必须是绝对路径,\\?\ 不认相对路径 全程用反斜杠 \,不能混用正斜杠 UNC 路径(\\server\share\...)要写成 \\?\UNC\server\share\...这是数据管线、爬虫抓文件时最常用的做法,不依赖系统设置。 方案三:从源头缩短 工程上最优雅的还是让路径变短,两个方向: 把项目往盘根挪 D:\workspace\company_project\data\cache\... ❌ D:\d\cache\... ✅ 少几十字符缩短目录命名 自动生成的目录名往往长得离谱: CAM_PBQ_FRONT_WIDE_RESET_OPTICAL_H110_HR ❌ CAM1 ✅用一个 mapping 文件记录原名 → 短名即可。 npm / git 也会踩 不止 Python:git clone 遇到超深仓库 → 加: git config --system core.longpaths truenpm install / pnpm install 的 node_modules 层级太深 → 系统开 LongPathsEnabled + 项目挪到盘根一句话总结 **能开注册表就开、能加 \\?\ 就加、能挪盘根就挪。** 三管齐下才彻底摆脱 WinError 206。
