amber-lang / amber-lang/bash2amber
[Detail Bug] Converter: `cd` without args / with `-` or `--` fails to change working directory
- 主要语言
- Rust
- 星标
- 2
- 派生
- 0
- PR 合并指标
- 30 天内没有已合并 PR
描述
# Summary
- **Context**: `src/amber/builtins/cd.rs` is responsible for converting the Bash `cd` builtin command into the equivalent Amber `cd` keyword.
- **Bug**: The renderer returns `None` when `cd` is called without arguments, with the `-` argument, or with any argument starting with `-` (including `--`).
- **Actual vs. expected**: When the renderer returns `None`, the system falls back to a subshell command (e.g., `trust $ cd $`), which has no effect on the working directory of the parent Amber process; it should instead be converted to an Amber-native directory change (e.g., `cd(env_var_get("HOME"))` or a supported Amber `cd` expression).
- **Impact**: Converted scripts that rely on `cd` to change the working directory will silently fail to do so for these common patterns, leading to subsequent commands being executed in the wrong directory, which can cause data loss or incorrect behavior.
# Code with bug
```rust
pub(crate) fn render(simple: &SimpleCommand, ctx: &RenderContext) -> Option {
if simple.words.len() < 2 {
return None; // <-- BUG 🔴 [cd with no arguments falls back to a no-op subshell]
}
let args: Vec<&String> = simple.words.iter().skip(1).collect();
for arg in &args {
if arg.starts_with('-') {
return None; // <-- BUG 🔴 [cd - or cd -- also fall back to no-op subshells]
}
}
let path = word_to_expr(args[0], ctx)?;
Some(format!("cd({path})"))
}
```
# Evidence
### 1. Reproduction with no arguments
Running the converter on a script containing `cd` followed by `pwd` shows that `cd` is converted to a subshell command while `pwd` is converted to a native Amber call.
**Input (`repro.sh`):**
```bash
cd
pwd
```
**Execution:**
```bash
cargo run -- repro.sh
```
**Output:**
```amber
trust $ cd $
pwd()
```
In Amber (and most shells), `trust $ cd $` executes `cd` in a child process, which cannot affect the current working directory of the script. Consequently, the following `pwd()` will report the same directory as before the `cd` command, whereas in Bash it would have changed to the user's home directory.
### 2. Reproduction with `cd -`
**Input (`repro_dash.sh`):**
```bash
cd -
```
**Execution:**
```bash
cargo run -- repro_dash.sh
```
**Output:**
```amber
trust $ cd - $
```
Again, this executes in a subshell and fails to change the directory of the running script.
### 3. Verification of Amber's `cd` behavior
Testing a generated Amber script shows that the `cd` keyword correctly changes the directory when provided with a path, but the `trust $ cd $` fallback does not.
```bash
# Correct behavior with path
echo 'cd "/tmp"' > test_success.ab
amber run test_success.ab # Success
# Failure of fallback mechanism
echo 'trust $ cd /tmp $; trust $ pwd $' > test_fallback.ab
amber run test_fallback.ab # Prints the current directory, NOT /tmp
```
# Why has this bug gone undetected?
This bug has likely gone undetected because many simple scripts use `cd` with an explicit path (e.g., `cd /var/log`), which is handled correctly by the current implementation. Users might also not notice that a directory change failed if subsequent commands use absolute paths or if the script doesn't happen to rely on the side effect of `cd` in the specific environment where it's tested.
# Recommended fix
The `cd` renderer should handle the case where `simple.words.len() == 1` by producing a native Amber command to change to the home directory. It should also handle the `-` argument by changing to the previous working directory (if supported by Amber) or at least provide a warning/error during conversion rather than falling back to a misleading no-op subshell. Additionally, it should handle the `--` sentinel correctly by treating the following argument as a path even if it starts with a hyphen.
```rust
pub(crate) fn render(simple: &SimpleCommand, ctx: &RenderContext) -> Option {
if simple.words.len() == 1 {
// Handle cd without arguments
return Some("cd(env_var_get(\"HOME\"))".to_string()); // <-- FIX 🟢
}
// ... handle '-' and '--' ...
}
```
# History
This bug was introduced in commit cb1f758 (@Ph0enixKM, 2026-02-13). The commit aimed to implement basic builtin command rendering, but the `cd` implementation was overly restrictive, returning `None` for calls without arguments or with flags, which triggers a subshell fallback that doesn't persist directory changes.
贡献指南
这个仓库没有索引到贡献指南
评估
这个 Issue 还没有评估数据。