跨平台CLI工具my-command的目录存储实现方案问询
Great question! Building cross-platform CLI tools that persist user data can feel a bit tricky at first, but there’s a straightforward, standard approach that works seamlessly across Linux, macOS, and Windows. Let’s break this down step by step.
Forget using environment variables—they’re session-specific (disappear when the terminal closes unless users manually add them to their shell config, which is a hassle). Instead, we’ll store the parked directory in a platform-standard user config folder. Every OS has a dedicated, persistent location for app settings, and we can auto-detect that path to keep things consistent.
1. Identify Cross-Platform Config Paths
Each OS follows a standard for where apps should store config data:
- Linux: Follows the XDG Base Directory spec—use
$XDG_CONFIG_HOMEif set, otherwise default to~/.config - macOS: Native convention is
~/Library/Application Support(you can also support XDG for consistency, but the native path feels more familiar to macOS users) - Windows: Uses
%APPDATA%(usually resolves toC:\Users\<YourUsername>\AppData\Roaming)
Your CLI can use language-specific utilities to fetch this path automatically (no hardcoding paths!).
2. Build the park Command
When a user runs my-command park:
- Grab the current working directory (CWD)
- Create the config folder if it doesn’t exist (recursively, so parent folders are created too)
- Write the CWD to a simple file in that config folder (e.g.,
parked_dir.txt—plain text is fine for this use case, or JSON if you want to expand later)
3. Build the show-dir Command
When a user runs my-command show-dir:
- Check for the parked directory file in the config folder
- If it exists, read and print the stored path
- If it doesn’t exist, show a friendly error telling the user to run
parkfirst
Here’s a simplified working example using Node.js (it uses only built-in modules, no external dependencies):
const os = require('os'); const path = require('path'); const fs = require('fs').promises; // Get the OS-specific config directory for our CLI function getConfigDir() { switch (process.platform) { case 'win32': return path.join(os.homedir(), 'AppData', 'Roaming', 'my-command'); case 'darwin': return path.join(os.homedir(), 'Library', 'Application Support', 'my-command'); case 'linux': const xdgConfig = process.env.XDG_CONFIG_HOME || path.join(os.homedir(), '.config'); return path.join(xdgConfig, 'my-command'); default: throw new Error(`Unsupported platform: ${process.platform}`); } } // Handle the `park` command async function handlePark() { const currentDir = process.cwd(); const configDir = getConfigDir(); // Create config directory if it doesn't exist await fs.mkdir(configDir, { recursive: true }); const parkedFile = path.join(configDir, 'parked_dir.txt'); await fs.writeFile(parkedFile, currentDir, 'utf8'); console.log(`Successfully parked directory: ${currentDir}`); } // Handle the `show-dir` command async function handleShowDir() { const configDir = getConfigDir(); const parkedFile = path.join(configDir, 'parked_dir.txt'); try { const parkedDir = await fs.readFile(parkedFile, 'utf8'); console.log(parkedDir.trim()); } catch (err) { if (err.code === 'ENOENT') { console.error('No directory has been parked yet! Run `my-command park` first.'); } else { console.error('Failed to read parked directory:', err.message); } } } // Parse command-line arguments and run the right command async function main() { const [command] = process.argv.slice(2); switch (command) { case 'park': await handlePark(); break; case 'show-dir': await handleShowDir(); break; default: console.error(`Unknown command: ${command}`); console.log('Available commands: park, show-dir'); } } main().catch(err => console.error(err));
- Python: Use the
appdirslibrary (pip install appdirs) to fetch the config path,os.getcwd()to get the current directory, and standard file I/O to read/write the path. - Go: Use
os.UserConfigDir()to get the standard config path,os.Getwd()for the current directory, andos.Create()/os.ReadFile()for file operations.
As mentioned earlier, env vars are temporary—they only last for the current terminal session. Storing the path in a config file keeps it persistent across reboots and terminal sessions without requiring users to modify their shell config files (like .bashrc or .zshrc), which is a much better user experience.
- Always handle file I/O errors (e.g., permission issues, full disk) to avoid crashes.
- If you plan to expand your CLI later, consider using JSON instead of plain text to store multiple values (like multiple parked directories).
- Test on all three target platforms to ensure the config path detection works as expected.
内容的提问来源于stack exchange,提问作者ajthinking

