Shells in OCaml
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

Rename to msh

This renames the shell to msh and adds plenty of package info.

+121 -69
+2
README.md
··· 2 2 ----- 3 3 4 4 A library for building shells in OCaml. 5 + 6 + Comes with a default, experimental POSIX shell called `msh`.
+39 -10
dune-project
··· 5 5 (generate_opam_files true) 6 6 7 7 (source 8 - (uri https://tangled.org/patrick.sirref.org/merry)) 8 + (uri git+https://tangled.org/patrick.sirref.org/merry)) 9 9 10 10 (authors "Patrick Ferris <patrick@sirref.org>") 11 + 11 12 (maintainers "Patrick Ferris <patrick@sirref.org>") 12 13 13 - (license LICENSE) 14 + (license ISC) 14 15 15 16 (documentation https://url/to/documentation) 16 17 ··· 18 19 (name merry) 19 20 (synopsis "A shell library") 20 21 (description "A library for writing shells") 21 - (depends ocaml) 22 + (depends 23 + morbig 24 + linenoise 25 + (yojson 26 + (>= 2.2.2)) 27 + (ppxlib 28 + (>= 0.37.0)) 29 + (ppx_deriving_yojson 30 + (>= 3.10.0)) 31 + (globlon 32 + (>= 0)) 33 + (fpath 34 + (>= 0.7.3)) 35 + (eio_posix 36 + (= "dev")) 37 + (eio 38 + (= "dev")) 39 + (cmdliner 40 + (>= 1.3.0)) 41 + ocaml) 22 42 (tags 23 43 ("add topics" "to describe" your project))) 24 44 25 45 (package 26 - (name osh) 27 - (synopsis "A shell") 28 - (description "osh is a shell written completely in OCaml using the merry library") 29 - (depends 30 - merry 31 - eio_main)) 32 - ; See the complete stanza docs at https://dune.readthedocs.io/en/stable/reference/dune-project/index.html 46 + (name msh) 47 + (synopsis "A shell") 48 + (description 49 + "msh is a shell written completely in OCaml using the merry library") 50 + (depends 51 + (eio 52 + (and 53 + (>= 1.3) 54 + :with-test)) 55 + (fmt 56 + (>= 0.11.0)) 57 + (eio_posix 58 + (>= 1.3)) 59 + (cmdliner 60 + (>= 1.3.0)) 61 + merry))
+16 -2
merry.opam
··· 4 4 description: "A library for writing shells" 5 5 maintainer: ["Patrick Ferris <patrick@sirref.org>"] 6 6 authors: ["Patrick Ferris <patrick@sirref.org>"] 7 - license: "LICENSE" 7 + license: "ISC" 8 8 tags: ["add topics" "to describe" "your" "project"] 9 9 doc: "https://url/to/documentation" 10 10 depends: [ 11 11 "dune" {>= "3.20"} 12 + "morbig" 13 + "linenoise" 14 + "yojson" {>= "2.2.2"} 15 + "ppxlib" {>= "0.37.0"} 16 + "ppx_deriving_yojson" {>= "3.10.0"} 17 + "globlon" {>= "0"} 18 + "fpath" {>= "0.7.3"} 19 + "eio_posix" {= "dev"} 20 + "eio" {= "dev"} 21 + "cmdliner" {>= "1.3.0"} 12 22 "ocaml" 13 23 "odoc" {with-doc} 14 24 ] ··· 26 36 "@doc" {with-doc} 27 37 ] 28 38 ] 29 - dev-repo: "https://tangled.org/patrick.sirref.org/merry" 39 + dev-repo: "git+https://tangled.org/patrick.sirref.org/merry" 30 40 x-maintenance-intent: ["(latest)"] 41 + pin-depends:[ 42 + [ "eio.dev" "git+https://github.com/ocaml-multicore/eio#c44ee5ce96c120b7ccc23a12d241dc8672e2888f" ] 43 + [ "eio_posix.dev" "git+https://github.com/ocaml-multicore/eio#c44ee5ce96c120b7ccc23a12d241dc8672e2888f" ] 44 + ]
+4
merry.opam.template
··· 1 + pin-depends:[ 2 + [ "eio.dev" "git+https://github.com/ocaml-multicore/eio#c44ee5ce96c120b7ccc23a12d241dc8672e2888f" ] 3 + [ "eio_posix.dev" "git+https://github.com/ocaml-multicore/eio#c44ee5ce96c120b7ccc23a12d241dc8672e2888f" ] 4 + ]
+7 -4
osh.opam msh.opam
··· 2 2 opam-version: "2.0" 3 3 synopsis: "A shell" 4 4 description: 5 - "osh is a shell written completely in OCaml using the merry library" 5 + "msh is a shell written completely in OCaml using the merry library" 6 6 maintainer: ["Patrick Ferris <patrick@sirref.org>"] 7 7 authors: ["Patrick Ferris <patrick@sirref.org>"] 8 - license: "LICENSE" 8 + license: "ISC" 9 9 doc: "https://url/to/documentation" 10 10 depends: [ 11 11 "dune" {>= "3.20"} 12 + "eio" {>= "1.3" & with-test} 13 + "fmt" {>= "0.11.0"} 14 + "eio_posix" {>= "1.3"} 15 + "cmdliner" {>= "1.3.0"} 12 16 "merry" 13 - "eio_main" 14 17 "odoc" {with-doc} 15 18 ] 16 19 build: [ ··· 27 30 "@doc" {with-doc} 28 31 ] 29 32 ] 30 - dev-repo: "https://tangled.org/patrick.sirref.org/merry" 33 + dev-repo: "git+https://tangled.org/patrick.sirref.org/merry" 31 34 x-maintenance-intent: ["(latest)"]
+2 -2
src/bin/dune
··· 1 1 (executable 2 - (public_name osh) 3 - (package osh) 2 + (public_name msh) 3 + (package msh) 4 4 (name main) 5 5 (libraries merry merry.posix eio_posix cmdliner fmt.tty))
+1 -1
src/bin/main.ml
··· 74 74 `P "Report bugs at https://tangled.org/patrick.sirref.org/merry/issues."; 75 75 ] 76 76 in 77 - Cmd.make (Cmd.info "osh" ~version:"v0.0.1" ~doc ~man) 77 + Cmd.make (Cmd.info "msh" ~version:"v0.0.1" ~doc ~man) 78 78 @@ 79 79 let+ command = command and+ dump = dump and+ file = file in 80 80 sh ~command ~dump ~file env
+3 -3
test/async.t
··· 1 1 Asynchronous jobs are tricky. For now, we disable them behind a flag in [set]. 2 2 3 - $ osh -c "echo hello &" 3 + $ msh -c "echo hello &" 4 4 You are using asynchronous operators and [set -o async] has not been called. 5 5 [1] 6 6 7 7 But we do have some support for them. 8 8 9 - $ cat > osh.sh << EOF 9 + $ cat > msh.sh << EOF 10 10 > set -o async 11 11 > sleep 10000 & echo hello 12 12 > kill -9 \$! ··· 19 19 20 20 $ sh test.sh 21 21 hello 22 - $ osh osh.sh 22 + $ msh msh.sh 23 23 hello
+4 -4
test/built_ins.t
··· 2 2 3 3 1. Cd 4 4 5 - $ osh -c "cd /usr; pwd" 5 + $ msh -c "cd /usr; pwd" 6 6 /usr 7 7 8 - $ osh -c "mkdir testing; cd testing; ls -a" 8 + $ msh -c "mkdir testing; cd testing; ls -a" 9 9 . 10 10 .. 11 11 12 12 2. Exit 13 13 14 - $ osh -c "exit 123" 14 + $ msh -c "exit 123" 15 15 exit 16 16 [123] 17 17 18 - $ osh -c "exit" 18 + $ msh -c "exit" 19 19 exit 20 20 21 21 2. Wait
+2 -2
test/dune
··· 1 1 (cram 2 - (package osh) 3 - (deps %{bin:osh})) 2 + (package msh) 3 + (deps %{bin:msh})) 4 4 5 5 (test 6 6 (name test_merry)
+7 -7
test/forloops.t
··· 3 3 4 4 1.1 Simple loop without needing to expand 5 5 6 - $ osh -c "for i in a b c; do echo hello; done" 6 + $ msh -c "for i in a b c; do echo hello; done" 7 7 hello 8 8 hello 9 9 hello ··· 11 11 12 12 1.2. Simple word list to echo 13 13 14 - $ osh -c "for foo in a b c; do echo \$foo; done" 14 + $ msh -c "for foo in a b c; do echo \$foo; done" 15 15 a 16 16 b 17 17 c ··· 22 22 $ sh -c "for foo in *.txt; do echo \$foo; done" 23 23 hello.txt 24 24 world.txt 25 - $ osh -c "for foo in *.txt; do echo \$foo; done" 25 + $ msh -c "for foo in *.txt; do echo \$foo; done" 26 26 hello.txt 27 27 world.txt 28 28 ··· 32 32 > echo hello > abc.md 33 33 > echo world > def.md 34 34 > for f in *.md; do 35 - > cmarkit html --unsafe -e -c -h -k "\$f" > "\$(basename -- "\$f" .md).html" 35 + > rev "\$f" > "\$(basename -- "\$f" .md).rev" 36 36 > done 37 37 > EOF 38 38 39 - $ osh test.sh 39 + $ msh test.sh 40 40 $ ls 41 - abc.html 42 41 abc.md 43 - def.html 42 + abc.rev 44 43 def.md 44 + def.rev 45 45 hello.txt 46 46 test.sh 47 47 world.txt
+2 -2
test/if.t
··· 7 7 > fi 8 8 > EOF 9 9 10 - $ osh test.sh 10 + $ msh test.sh 11 11 hello 12 12 world 13 13 ··· 22 22 23 23 $ sh test.sh 24 24 goodbye 25 - $ osh test.sh 25 + $ msh test.sh 26 26 goodbye
+2 -2
test/paths.t
··· 2 2 particular, things like globbing. 3 3 4 4 $ touch hello.txt; touch world.txt 5 - $ osh -c "basename --suffix='.txt' *.txt" 5 + $ msh -c "basename --suffix='.txt' *.txt" 6 6 hello 7 7 world 8 8 $ touch Hello.txt 9 - $ osh -c "basename --suffix='.txt' ?ello.txt" 9 + $ msh -c "basename --suffix='.txt' ?ello.txt" 10 10 Hello 11 11 hello
+3 -3
test/pipelines.t
··· 11 11 ls: invalid option -- 'j' 12 12 Try 'ls --help' for more information. 13 13 hello 14 - $ osh -c "ls -j" 14 + $ msh -c "ls -j" 15 15 ls: invalid option -- 'j' 16 16 Try 'ls --help' for more information. 17 17 [2] 18 - $ osh -c "ls -j | sleep 0.1; ls" 18 + $ msh -c "ls -j | sleep 0.1; ls" 19 19 ls: invalid option -- 'j' 20 20 Try 'ls --help' for more information. 21 21 hello ··· 25 25 $ sh -c "! exit 1 | ls" 26 26 hello 27 27 [1] 28 - $ osh -c "! exit 1 | ls" 28 + $ msh -c "! exit 1 | ls" 29 29 hello 30 30 [1]
+24 -24
test/simple.t
··· 1 - A series of simple shell scripting tests for osh. 1 + A series of simple shell scripting tests for msh. 2 2 3 3 1. Variables and Parameters 4 4 ··· 9 9 > echo \$P 10 10 > EOF 11 11 12 - $ osh test.sh 12 + $ msh test.sh 13 13 hello world 14 14 15 15 $ cat >test.sh <<EOF 16 16 > FOO=bar 17 17 > echo "\$FOO" 18 18 > EOF 19 - $ osh test.sh 19 + $ msh test.sh 20 20 bar 21 21 22 - $ osh -c "FOO=bar echo \$FOO" 22 + $ msh -c "FOO=bar echo \$FOO" 23 23 24 - $ osh -c "FOO=bar; echo \$FOO" 24 + $ msh -c "FOO=bar; echo \$FOO" 25 25 bar 26 26 27 - $ osh -c "FOO=~/foo; echo \$FOO" 27 + $ msh -c "FOO=~/foo; echo \$FOO" 28 28 /home/patrick/foo 29 29 30 - $ osh -c "FOO=~/foo env | grep FOO" 30 + $ msh -c "FOO=~/foo env | grep FOO" 31 31 FOO=/home/patrick/foo 32 32 33 33 $ cat >test.sh << EOF ··· 39 39 $ sh test.sh 40 40 hello 41 41 VAR2: world () 42 - $ osh test.sh 42 + $ msh test.sh 43 43 hello 44 44 VAR2: world () 45 45 46 46 $ sh -c "FOO=abc env | grep FOO; env | grep FOO" 47 47 FOO=abc 48 48 [1] 49 - $ osh -c "FOO=abc env | grep FOO; env | grep FOO" 49 + $ msh -c "FOO=abc env | grep FOO; env | grep FOO" 50 50 FOO=abc 51 51 [1] 52 52 ··· 58 58 > sh -c "exit 1" || echo hello 59 59 > EOF 60 60 61 - $ osh test.sh 61 + $ msh test.sh 62 62 hello 63 63 64 64 2.2 Simple And ··· 67 67 > sh -c "exit 1" && echo hello 68 68 > EOF 69 69 70 - $ osh test.sh 70 + $ msh test.sh 71 71 [1] 72 72 73 73 2.3 Simple And and Or ··· 76 76 > echo first || sh -c "echo never && exit 1" && echo second 77 77 > EOF 78 78 79 - $ osh test.sh 79 + $ msh test.sh 80 80 first 81 81 second 82 82 83 83 2.4 Simple Pipeline 84 84 85 - $ osh -c "echo hello | rev" 85 + $ msh -c "echo hello | rev" 86 86 olleh 87 - $ osh -c "echo hello | rev | rev | rev | rev" 87 + $ msh -c "echo hello | rev | rev | rev | rev" 88 88 hello 89 89 90 90 2.5 Input redirection ··· 96 96 > --------------- 97 97 > EOF 98 98 99 - $ osh -c "cat < hello.md" 99 + $ msh -c "cat < hello.md" 100 100 # Hello, World! 101 101 --------------- 102 102 103 103 Using `<&-` to close stdin 104 104 105 - $ osh -c "cat <&-" 105 + $ msh -c "cat <&-" 106 106 cat: -: Bad file descriptor 107 107 cat: closing standard input: Bad file descriptor 108 108 [1] 109 109 110 110 Using `<&` to copy a file descriptor 111 111 112 - $ osh -c "cat 3<hello.md <&3" 112 + $ msh -c "cat 3<hello.md <&3" 113 113 # Hello, World! 114 114 --------------- 115 115 116 116 But also, some simple errors should work too. 117 117 118 - $ osh -c "cat <1" 119 - osh: internal error, uncaught exception: 118 + $ msh -c "cat <1" 119 + msh: internal error, uncaught exception: 120 120 Eio.Io Fs Not_found Unix_error (No such file or directory, "openat", "1"), 121 121 opening <fs:1> 122 122 ··· 126 126 127 127 Simple example of redirecting some output 128 128 129 - $ osh -c "echo hello > hello.txt && cat hello.txt" 129 + $ msh -c "echo hello > hello.txt && cat hello.txt" 130 130 hello 131 131 $ stat --format="%A" hello.txt 132 132 -rw-r--r-- 133 133 134 134 Simple appending example 135 135 136 - $ osh -c "echo world >> hello.txt && cat hello.txt" 136 + $ msh -c "echo world >> hello.txt && cat hello.txt" 137 137 hello 138 138 world 139 139 140 140 Redirection of fds 141 141 142 - $ osh -c "echo hello 3>out.txt >&3" 142 + $ msh -c "echo hello 3>out.txt >&3" 143 143 $ cat out.txt 144 144 hello 145 145 ··· 147 147 148 148 A simple, semicolon sequence. 149 149 150 - $ osh -c "echo hello; echo world; echo 'that is all'" 150 + $ msh -c "echo hello; echo world; echo 'that is all'" 151 151 hello 152 152 world 153 153 that is all ··· 158 158 > echo 'that is all' 159 159 > EOF 160 160 161 - $ osh test.sh 161 + $ msh test.sh 162 162 hello 163 163 world 164 164 that is all
+3 -3
test/subshell.t
··· 5 5 $ cat > test.md << EOF 6 6 > Just some text here 7 7 > EOF 8 - $ osh -c "cat '$(echo test.md)'" 8 + $ msh -c "cat '$(echo test.md)'" 9 9 Just some text here 10 10 11 - $ osh -c "'$(which echo)' hello" 11 + $ msh -c "'$(which echo)' hello" 12 12 hello 13 - $ osh -c "`which echo` hello" 13 + $ msh -c "`which echo` hello" 14 14 hello