Initial commit: psh - minimal bash-like shell with && || operators and tab completion

这个提交包含在:
Paze SH
2026-08-16 12:25:26 +08:00
当前提交 a787f65b8f
修改 7 个文件,包含 1355 行新增0 行删除
+27
查看文件
@@ -0,0 +1,27 @@
CC = gcc
CFLAGS = -Wall -Wextra -std=c99 -O2
LDFLAGS =
TARGET = psh.exe
SRC = psh.c
.PHONY: all clean test
all: $(TARGET)
$(TARGET): $(SRC)
$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
test: $(TARGET)
@echo "Testing psh..."
./$(TARGET) -c "echo hello"
./$(TARGET) -c "pwd"
./$(TARGET) -c "dir | findstr .exe"
@echo "Tests passed!"
clean:
rm -f $(TARGET) *.o
# Build with readline support (if available)
readline: $(SRC)
$(CC) $(CFLAGS) -DHAVE_READLINE -lreadline -o $(TARGET) $(SRC)
+115
查看文件
@@ -0,0 +1,115 @@
# psh - A minimal bash-like shell in pure C
A lightweight POSIX shell implementation featuring:
- Command execution via fork/exec (Windows: CreateProcess)
- Built-in commands: `cd`, `pwd`, `echo`, `exit`, `help`, `env`
- Input/output redirection (`<`, `>`, `>>`)
- Piping (`|`)
- Background execution (`&`)
- Command history with up/down arrows
- Tab completion
- `&&` and `||` operators
- Basic environment variable support
- Tilde expansion (`~`)
## Building
```bash
make
```
Requires:
- GCC or compatible C compiler
- GNU Readline library (for line editing)
## Running
```bash
./psh
```
## Features
### Built-ins
- `cd [dir]` - Change directory
- `pwd` - Print working directory
- `echo [args]` - Print text (supports `$VAR` expansion)
- `exit` - Exit shell
- `help` - Show help
- `env [var=val]` - Show or set environment variables
- `history` - Show command history
### Redirection
```bash
ls > output.txt # Redirect output
cat < input.txt # Redirect input
echo hi >> log.txt # Append output
```
### Piping
```bash
ps aux | grep python | wc -l
```
### Background
```bash
sleep 100 &
```
### Logical Operators
```bash
cmd1 && cmd2 # Execute cmd2 only if cmd1 succeeds
cmd1 || cmd2 # Execute cmd2 only if cmd1 fails
```
### Tab Completion
Press `Tab` to complete commands:
- Built-in commands (cd, pwd, echo, etc.)
- Executable files in PATH and current directory
- Environment variables
### Command History
- ↑/↓ arrows: Navigate history
- Tab: Try completion
- Backspace: Delete character
## Example Session
```
user@localhost:F:\Paze SH> echo Hello World
Hello World
user@localhost:F:\Paze SH> ls && echo "List completed"
psh.c README.md Makefile
List completed
user@localhost:F:\Paze SH> false || echo "Fallback executed"
Fallback executed
user@localhost:F:\Paze SH> help
psh - minimal bash-like shell (Windows)
Built-in commands:
cd [dir] Change directory
pwd Print working directory
echo [args] Print arguments
exit Exit shell
env [var=val] Show/set environment
help Show this help
Features:
cmd1 | cmd2 Pipe output
cmd > file Redirect output
cmd >> file Append output
cmd < file Redirect input
cmd & Run in background
cmd1 && cmd2 Execute cmd2 if cmd1 succeeds
cmd1 || cmd2 Execute cmd2 if cmd1 fails
history View command history
Tab Try command completion
```
## License
MIT
+1121
查看文件
文件差异内容过多而无法显示 加载差异
二进制
查看文件
二进制文件未显示。
+84
查看文件
@@ -0,0 +1,84 @@
/*
* psh - Test cases for the shell
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
/* Test helper */
int run_test(const char *cmd, const char *expected_substring) {
char output[4096];
FILE *fp;
int passed = 0;
printf("Testing: %s\n", cmd);
/* Run command and capture output */
char full_cmd[4096];
snprintf(full_cmd, sizeof(full_cmd), "psh.exe -c \"%s\" 2>&1", cmd);
fp = _popen(full_cmd, "r");
if (fp == NULL) {
printf(" FAILED: Could not execute command\n");
return 0;
}
memset(output, 0, sizeof(output));
if (fread(output, 1, sizeof(output) - 1, fp) > 0) {
/* Remove trailing newline */
output[strcspn(output, "\n")] = '\0';
if (strstr(output, expected_substring) != NULL) {
printf(" PASSED: Got expected output containing '%s'\n", expected_substring);
passed = 1;
} else {
printf(" FAILED: Expected output containing '%s', got: '%s'\n", expected_substring, output);
}
} else {
printf(" FAILED: No output from command\n");
}
_pclose(fp);
return passed;
}
int main() {
int passed = 0;
int total = 0;
printf("=== psh Test Suite ===\n\n");
/* Test 1: echo */
total++;
if (run_test("echo hello", "hello")) passed++;
/* Test 2: pwd */
total++;
if (run_test("pwd", "F:\\Paze SH")) passed++;
/* Test 3: environment variables */
total++;
if (run_test("echo $HOME", "")) passed++; /* Just check it doesn't crash */
/* Test 4: help */
total++;
if (run_test("help", "Built-in commands")) passed++;
/* Test 5: history (empty) */
total++;
if (run_test("history", "history")) passed++;
/* Test 6: && operator */
total++;
if (run_test("echo first && echo second", "first")) passed++;
/* Test 7: || operator */
total++;
if (run_test("false || echo fallback", "fallback")) passed++;
printf("\n=== Results: %d/%d tests passed ===\n", passed, total);
return (passed == total) ? 0 : 1;
}
二进制
查看文件
二进制文件未显示。
+8
查看文件
@@ -0,0 +1,8 @@
test1: echo Hello World
test2: pwd
test3: ls | findstr .exe
test4: echo $HOME
test5: mkdir testdir && cd testdir && pwd
test6: false || echo "This should print"
test7: true && echo "This should also print"
test8: env