HackerOS Shell.
hsh to nowoczesna powłoka napisana w całości w Rust — szybka, bezpieczna i gotowa
do codziennej pracy bez fallbacku do /bin/sh.
Obsługuje pełne skryptowanie POSIX, natywne potoki, kolorowanie składni i inteligentne podpowiedzi.
Pierwsze kroki
hsh uruchamia się jak każda inna powłoka. Można go ustawić jako domyślną powłokę lub uruchamiać bezpośrednio.
# Uruchomienie interaktywne hsh # Wykonanie pojedynczego polecenia hsh -c 'echo "hello hsh"' # Dry-run — sprawdź co zostałoby wykonane hsh --dry-run # Wersja hsh --version # Ustawienie jako domyślna powłoka chsh -s $(which hsh)
Główne funkcje
$(( )): operatory, potęgowanie, porównania, zmienne.Budowa promptu
Prompt hsh składa się z segmentów, które wyświetlają się kontekstowo — pojawią się tylko gdy są istotne.
| Segment | Zawartość | Warunek wyświetlenia |
|---|---|---|
| 17:42:11 | Aktualny czas HH:MM:SS | zawsze |
| ~/projects | Skrócona ścieżka (~ zamiast $HOME) | zawsze |
| (⎇ main ✗) | Gałąź git + status dirty/ahead/behind | w repozytorium git |
| ✗ [1] | Exit code ostatniej komendy | kod ≠ 0 |
| 2.3s | Czas wykonania komendy | czas ≥ 2000ms |
| cpu:72% mem:85% | Obciążenie systemu | CPU > 70% lub RAM > 80% |
| ⚡ | Tryb root | uid == 0 |
| [2] | Głębokość zagnieżdżenia powłoki | HSH_DEPTH > 0 |
| ❯ | Znak zachęty (zielony/czerwony) | zawsze |
Kolory git
| Stan | Kolor | Znaczenie |
|---|---|---|
| zielony | ● | Czyste drzewo robocze, zsynchronizowane z remote |
| żółty | ● | Są commity do push/pull (ahead/behind) |
| czerwony | ● | Niezacommitowane zmiany (dirty) |
Zmienne powłoki
Ustawianie i odczyt
# Zmienna lokalna (widoczna tylko w hsh) FOO=bar # Eksport do środowiska export FOO=bar # Inline — tylko dla jednej komendy LANG=pl_PL.UTF-8 man grep # Odczyt echo $FOO echo ${FOO}
Modyfikatory
# Wartość domyślna gdy pusta/nieustawiona echo ${FOO:-domyślna} # Alternatywa gdy ustawiona echo ${FOO:+alternatywa} # Błąd gdy pusta (przerywa skrypt przy -e) echo ${FOO:?Zmienna FOO jest wymagana}
Zmienne specjalne
| Zmienna | Znaczenie |
|---|---|
| $? | Exit code ostatniej komendy |
| $$ | PID bieżącego procesu hsh |
| $0 | Nazwa powłoki (hsh) |
| $# | Liczba argumentów pozycyjnych |
| $@, $* | Wszystkie argumenty pozycyjne |
| $1, $2, … | Kolejne argumenty pozycyjne |
| $RANDOM | Losowa liczba całkowita |
| $SECONDS | Sekundy od uruchomienia hsh |
| $PWD | Bieżący katalog |
| $OLDPWD | Poprzedni katalog (przed cd) |
Podstawianie komend
# Nowy styl (zalecany) FILES=$(ls *.rs) DATE=$(date +%Y-%m-%d) # Stary styl (backtick) HOST=`hostname` # W środku stringa echo "Dzisiaj: $(date)"
Arytmetyka $(( ))
hsh posiada własny parser wyrażeń arytmetycznych — nie wywołuje żadnego zewnętrznego procesu.
# Podstawowe działania echo $(( 2 + 3 )) # 5 echo $(( 10 / 3 )) # 3 (dzielenie całkowite) echo $(( 10 % 3 )) # 1 (modulo) echo $(( 2 ** 10 )) # 1024 (potęgowanie) # Ze zmiennymi x=5; y=3 echo $(( x * y + 1 )) # 16 # Przypisanie przez arytmetykę i=$(( i + 1 )) # Porównania (zwracają 0 lub 1) echo $(( x > y )) # 1 echo $(( x == 5 )) # 1 # Logika echo $(( x > 0 && y > 0 )) # 1 echo $(( x > 10 || y > 0 )) # 1 echo $(( !0 )) # 1 # Zagnieżdżone echo $(( (2 + 3) * (4 - 1) )) # 15
| Operator | Opis | Priorytet |
|---|---|---|
| || | Logiczne LUB | najniższy |
| && | Logiczne I | ↑ |
| == != < <= > >= | Porównania | ↑ |
| + - | Dodawanie, odejmowanie | ↑ |
| * / % | Mnożenie, dzielenie, modulo | ↑ |
| ** | Potęgowanie | ↑ |
| - ! | Jednoargumentowe: negacja, NOT | najwyższy |
** zwracają błąd i przerywają wyrażenie.
Przekierowania I/O
Wszystkie przekierowania są implementowane natywnie przez open() + dup2() — bez pośrednictwa /bin/sh.
# Nadpisz plik echo "hello" > output.txt # Dopisz do pliku echo "world" >> output.txt # Stdin z pliku grep error < log.txt # Stderr do pliku cmd 2> errors.log # Stderr → stdout (przekieruj stderr do stdout) cmd 2>&1 # Stdout i stderr razem do pliku cmd &> all.log # Dowolny deskryptor pliku cmd 3> custom.log cmd 3>&1
| Składnia | Działanie |
|---|---|
| > plik | stdout → plik (nadpisuje) |
| >> plik | stdout → plik (dopisuje) |
| < plik | stdin ← plik |
| 2> plik | stderr → plik |
| 2>&1 | stderr → tam gdzie stdout |
| &> plik | stdout + stderr → plik |
| N> plik | deskryptor N → plik |
| N>&M | deskryptor N → deskryptor M |
| << DELIM | heredoc — stdin z literału |
| <<- DELIM | heredoc z usuwaniem tabulatorów |
Potoki (pipelines)
hsh tworzy potoki przez natywne wywołanie pipe(2) — każdy etap to osobny proces połączony z następnym przez stdout/stdin.
# Prosty potok ls -la | grep .rs # Wielostopniowy cat log.txt | grep ERROR | sort | uniq | head -20 # Z przekierowaniami na końcu find . -name '*.rs' | wc -l > count.txt # Stderr w potoku cmd 2>&1 | grep error # Tylko natywne komendy (zero fork na /bin) find . | grep .rs | wc -l # Background pipeline long_cmd | process &
set -e niezerowy kod dowolnego etapu przerywa skrypt.
Skrypty i kontrola przepływu
hsh zawiera własny parser i interpreter AST — wszystkie konstrukty skryptowe działają bez wywoływania /bin/sh.
if / elif / else
if [ -f config.toml ]; then echo "plik istnieje" elif [ -d config/ ]; then echo "katalog istnieje" else echo "nic nie znaleziono" fi
for
# Iteracja po plikach (glob) for f in *.rs; do echo "kompilacja: $f" done # Iteracja po liczbach for i in 1 2 3 4 5; do echo $i done # Iteracja po wyjściu komendy for line in $(cat list.txt); do process $line done
while
i=0 while [ $i -lt 10 ]; do echo $i i=$(( i + 1 )) done
case
case $1 in start) echo "Uruchamianie..." ;; stop|halt) echo "Zatrzymywanie..." ;; *) echo "Użycie: $0 {start|stop}" ;; esac
Funkcje
# Definicja greet() { echo "Cześć, $1! Masz $# argumentów." } # Wywołanie greet Michał # Funkcja z logiką is_even() { return $(( $1 % 2 )) } if is_even 42; then echo "parzysta" fi
Operatory łączenia
# Wykonaj cmd2 tylko gdy cmd1 się powiodło make && ./run_tests # Wykonaj cmd2 tylko gdy cmd1 się nie powiodło ping -c1 server || echo "serwer niedostępny" # Zawsze oba build ; deploy
Opcje powłoki (set)
| Opcja | Opis |
|---|---|
| set -e | Przerwij skrypt gdy jakakolwiek komenda zwróci błąd (errexit) |
| set -x | Wypisuj każdą wykonywaną komendę z prefiksem + (xtrace) |
| set -u | Traktuj nieznane zmienne jako błąd (nounset) |
| set +e | Wyłącz errexit |
Heredoc <<
# Podstawowy heredoc (rozszerza zmienne) NAME=Michał cat << EOF Cześć, $NAME! Dzisiaj jest $(date +%A). EOF # Bez rozszerzania zmiennych (literal) cat << 'EOF' To $NIE zostanie rozwinięte. EOF # Usuwanie wiodących tabulatorów (<<-) cat <<- EOF Ta linia ma usunięty tab na początku. Ta też. EOF
$VAR i ${VAR}. Otocz delimiter cudzysłowem (<< 'EOF') żeby wyłączyć rozszerzanie.
Wbudowane komendy
| Komenda | Opis |
|---|---|
| cd [dir|-] | Zmień katalog. - wraca do poprzedniego ($OLDPWD). |
| exit [kod] | Wyjdź z hsh z podanym kodem wyjścia (domyślnie 0). |
| history [query] | Historia komend z timestampami. Z argumentem — fuzzy search. |
| which NAME | Pokaż typ komendy: builtin, alias, lub pełna ścieżka binarium. |
| type NAME | Alias dla which. |
| export KEY=VAL | Ustaw zmienną środowiskową. export -p wyświetla wszystkie. |
| alias | Wyświetl wszystkie zdefiniowane aliasy. |
| unalias NAME | Usuń alias (wymaga restartu — aliasy są ładowane z .hshrc). |
| set [-e|-x|-u] | Ustaw opcje powłoki: errexit, xtrace, nounset. |
| pushd [dir] | Wepchnij bieżący katalog na stos i przejdź do dir. |
| popd | Wyskocz katalog ze stosu i przejdź do niego. |
| dirs | Wyświetl stos katalogów. |
| source FILE | Wykonaj plik w bieżącym kontekście powłoki. |
| . FILE | Alias dla source. |
| test EXPR | Oceń wyrażenie warunkowe. Zwraca 0 (prawda) lub 1 (fałsz). |
| [ EXPR ] | Alias dla test. |
| jobs | Wyświetl listę zadań w tle. |
| fg [%id] | Przenieś zadanie na pierwszy plan. |
| bg [%id] | Wznów zadanie w tle. |
| stop [%id] | Zatrzymaj zadanie (SIGSTOP). |
| kill [-SIG] %id | Wyślij sygnał do zadania. |
| wait [%id] | Czekaj na zakończenie zadania. |
| hsh-help | Krótka pomoc wbudowana. |
| hsh-docs [temat] | Rozbudowana dokumentacja (w terminalu). |
| hsh-settings | Interaktywna zmiana motywu kolorystycznego. |
test — operatory
| Operator | Znaczenie |
|---|---|
| -f PLIK | Plik istnieje i jest plikiem regularnym |
| -d PLIK | Plik istnieje i jest katalogiem |
| -e PLIK | Plik istnieje (dowolny typ) |
| -r / -w / -x | Plik jest do odczytu / zapisu / wykonania |
| -z STR | String jest pusty |
| -n STR | String jest niepusty |
| -L PLIK | Plik jest dowiązaniem symbolicznym |
| -s PLIK | Plik ma rozmiar > 0 |
| A = B | Stringi są równe |
| A != B | Stringi są różne |
| A -eq B | Liczby równe |
| A -ne / -lt / -le / -gt / -ge B | Porównania liczbowe |
| ! EXPR | Negacja |
| EXPR -a EXPR | Logiczne I (AND) |
| EXPR -o EXPR | Logiczne LUB (OR) |
| A -nt B | Plik A nowszy niż B |
| A -ot B | Plik A starszy niż B |
Komendy natywne
Następujące komendy są zaimplementowane bezpośrednio w hsh — nie wywołują zewnętrznych binariów nawet gdy są dostępne w $PATH:
-n, sekwencje escape \n \t \r-l -a -h, kolorowanie typów plików-p (utwórz katalogi pośrednie)-r -rf -f-r -R, kopiowanie między urządzeniami-i -v -c -n, kolorowanie dopasowań-n N, wiele plików-l -w -c-a -s -n -r -m-name (glob) i -type{}%s %d %f %c i sekwencje \n \tZarządzanie zadaniami
# Uruchom w tle long_process & # [1] 1234 # Wyświetl zadania jobs # [1] Running 1234 long_process # Przenieś na pierwszy plan fg %1 # Wróć do tła # (Ctrl+Z zatrzymuje, bg wznawia) bg %1 # Wyślij sygnał kill %1 # SIGTERM kill -KILL %1 # SIGKILL kill -STOP %1 # zatrzymaj kill -CONT %1 # wznów # Czekaj na zakończenie wait %1
[1] Done (0) long_process
System podpowiedzi
hsh łączy trzy warstwy podpowiedzi inspirowane fish i zsh:
1. Historia inline (jak fish)
Wpisz kilka pierwszych liter — hsh sugeruje pełną komendę z historii jako szary tekst. Naciśnij → żeby zaakceptować.
2. Sekwencje (next-command prediction)
Na pustej linii hsh podpowiada komendę, którą zwykle wykonujesz po tej poprzedniej. Dane uczą się automatycznie z Twojej historii.
3. cd preview
Podczas wpisywania cd cz hsh wyświetla pasujące katalogi w bieżącym folderze bezpośrednio w hincie.
Spellcheck
Gdy komenda zwróci exit code 127 (nie znaleziono), hsh używa dystansu Levenshteina do zaproponowania poprawki:
gti status hsh: gti: command not found ❓ Czy chodziło Ci o: git status?
Dane SmartHints są zapisywane w ~/.hsh-hints.json i ładowane przy każdym uruchomieniu.
Uzupełnianie Tab
| Kontekst | Co uzupełnia Tab |
|---|---|
| Pierwsze słowo | Komendy z $PATH + builtins (posortowane, bez duplikatów) |
| Po git | add, commit -m, push origin, pull, status, log --oneline, branch, checkout, … |
| Po cargo | build, run, test, check, clippy, fmt, doc, publish, … |
| Po systemctl | start, stop, restart, enable, disable, status, … |
| Po apt | install, remove, update, upgrade, search, show, … |
| Po docker | run, build, pull, push, ps, images, stop, exec, logs, … |
| Po npm | install, run, start, test, build, publish, … |
| Po pip | install, uninstall, list, show, freeze, … |
| Po kubectl | get, apply, delete, describe, logs, exec, … |
| Ścieżki | Pliki i katalogi przez FilenameCompleter |
Skróty klawiszowe
hsh działa w trybie Emacs (domyślny). Wszystkie standardowe skróty Readline są dostępne.
| Skrót | Działanie |
|---|---|
| → / End | Zaakceptuj cały hint / uzupełnienie |
| Alt+F | Zaakceptuj jedno słowo hintu (forward-word) |
| Tab | Uzupełnij komendę, subkomendę lub ścieżkę |
| Ctrl+R | Wyszukiwanie wsteczne w historii (reverse search) |
| Ctrl+L | Wyczyść ekran |
| Ctrl+C | Przerwij bieżącą linię lub komendę |
| Ctrl+D | EOF — wyjdź z hsh |
| Ctrl+A | Skocz na początek linii |
| Ctrl+E | Skocz na koniec linii |
| Ctrl+W | Usuń słowo przed kursorem |
| Ctrl+U | Usuń od kursora do początku linii |
| Ctrl+K | Usuń od kursora do końca linii |
| Alt+B | Cofnij o jedno słowo |
| ↑ / ↓ | Poprzednia / następna komenda w historii |
| Ctrl+Z | Zatrzymaj bieżący proces (SIGSTOP) → użyj bg / fg |
Motywy kolorystyczne
Zmień motyw przez hsh-settings. Ustawienie zapisuje się natychmiast do ~/.config/hackeros/hsh/theme.json.
Konfiguracja .hshrc
Plik ~/.hshrc używa formatu .hk (HackerOS config). Ładowany przy każdym uruchomieniu interaktywnym.
# ── Aliasy ─────────────────────────────────────────────── [aliases] ll = "ls -lah" la = "ls -a" g = "git" gs = "git status" gp = "git push origin" gl = "git log --oneline --graph" v = "vim" py = "python3" dc = "docker compose" # ── Prompt ─────────────────────────────────────────────── [prompt] # Kolejność segmentów (eksperymentalne) segment_order = "time, dir, git, mem_cpu"
| Plik / Ścieżka | Zawartość |
|---|---|
| ~/.hshrc | Aliasy i konfiguracja promptu |
| ~/.hsh-history-ts.json | Historia z timestampami (JSON) |
| ~/.hsh-hints.json | Dane SmartHints (sekwencje, prefiksy) |
| ~/.hsh-path-cache.json | Cache komend z $PATH (TTL: 5 minut) |
| ~/.hsh-history | Historia dla rustyline (Ctrl+R) |
| ~/.config/hackeros/hsh/theme.json | Aktywny motyw kolorystyczny |
Bezpieczeństwo i ochrona
Niebezpieczne komendy
hsh automatycznie wykrywa i blokuje potencjalnie destruktywne komendy. Wymagają wpisania yes:
| Wzorzec | Ostrzeżenie |
|---|---|
rm -rf / | Usunięcie wszystkich plików |
rm -rf /* | Usunięcie wszystkich plików |
dd if=/dev/zero of=/dev/sda | Nadpisanie dysku |
:(){ :|:& };: | Fork bomb — crash systemu |
curl | sh | Zdalne wykonanie kodu |
wget -O- | bash | Zdalne wykonanie kodu |
chmod -R 777 / | Globalne uprawnienia 777 |
mkfs /dev/sda | Formatowanie dysku |
Auto-sudo dla edytorów
Gdy edytujesz plik w /etc/, /usr/, /var/ lub /boot/ przez vi, vim, nano lub emacs — hsh pyta czy chcesz użyć sudo.
Kolorowanie składni — detekcja
Niebezpieczne komendy są wizualnie oznaczane czerwonym migającym tłem już podczas wpisywania, zanim naciśniesz Enter.
Flagi startowe
| Flaga | Opis | Przykład |
|---|---|---|
| -c 'cmd' | Wykonaj komendę i wyjdź | hsh -c 'echo hello' |
| --dry-run | Symuluj — wypisz komendy zamiast wykonywać | hsh --dry-run |
| --version / -V | Wyświetl wersję i wyjdź | hsh --version |
Tryb dry-run
W trybie --dry-run żadna komenda nie jest wykonywana — hsh wypisuje tylko co by zostało wykonane:
❯ rm -rf build/ [dry-run] rm -rf build/ ❯ export DB_URL=postgres://localhost [dry-run] export DB_URL=postgres://localhost ❯ build.sh & [dry-run] [bg] build.sh
hsh --dry-run -c ./deploy.sh żeby zobaczyć pełną sekwencję operacji bez ryzyka.