{"id":14128153,"url":"https://github.com/jakubriegel/kotlin-shell","last_synced_at":"2025-07-13T23:06:16.594Z","repository":{"id":48395748,"uuid":"201264963","full_name":"jakubriegel/kotlin-shell","owner":"jakubriegel","description":"Tool for performing shell-like programing in Kotlin","archived":false,"fork":false,"pushed_at":"2021-07-30T13:28:57.000Z","size":246,"stargazers_count":143,"open_issues_count":4,"forks_count":8,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-04-14T03:13:34.034Z","etag":null,"topics":["jvm","kotlin","kotlin-library","pipeline","process-management","shell","shell-script"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jakubriegel.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-08-08T13:31:20.000Z","updated_at":"2025-02-25T17:34:04.000Z","dependencies_parsed_at":"2022-08-24T09:20:27.659Z","dependency_job_id":null,"html_url":"https://github.com/jakubriegel/kotlin-shell","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/jakubriegel/kotlin-shell","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jakubriegel%2Fkotlin-shell","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jakubriegel%2Fkotlin-shell/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jakubriegel%2Fkotlin-shell/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jakubriegel%2Fkotlin-shell/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jakubriegel","download_url":"https://codeload.github.com/jakubriegel/kotlin-shell/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jakubriegel%2Fkotlin-shell/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265218691,"owners_count":23729524,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["jvm","kotlin","kotlin-library","pipeline","process-management","shell","shell-script"],"created_at":"2024-08-15T16:01:20.304Z","updated_at":"2025-07-13T23:06:16.549Z","avatar_url":"https://github.com/jakubriegel.png","language":"Kotlin","funding_links":[],"categories":["Kotlin"],"sub_categories":[],"readme":"# Kotlin Shell\n\n## about\nKotlin Shell is a prototype tool for performing shell programming in Kotlin and Kotlin script.\nIt provides shell-like API which takes advantage of Kotlin features.\n\nFor examples go to the [examples](#examples) section.\n\n## intro\nCreating processes is extremly easy in Kotlin Shell:\n```kotlin\nshell {\n  \"echo hello world\"()\n}\n\n// echo hello world\n```\n\nPiping is also supported:\n```kotlin\nshell {\n  val toUpper = stringLambda { it.toUpper() to \"\" }\n  pipeline { file(\"data.txt\") pipe \"grep abc\".process() pipe toUpper }\n}\n\n// cat data.txt | grep abc | tr '[:lower:]' '[:upper:]'\n```\n\n## content\n* [about](#about)\n* [intro](#intro)\n* [content](#content)\n* [preliminary](#preliminary)\n* [how to get Kotlin Shell](#how-to-get-kotlin-shell)\n  + [for scripting](#for-scripting)\n  + [as library](#as-library)\n* [how to run the scripts](#how-to-run-the-scripts)\n  + [in Kotlin script](#in-kotlin-script)\n    - [kshell command](#kshell-command)\n      * [command line](#command-line)\n      * [shebang](#shebang)\n    - [kotlinc command](#kotlinc-command)\n  + [in Kotlin programs](#in-kotlin-programs)\n* [usage](#usage)\n  + [writing scripts](#writing-scripts)\n    - [in Kotlin code](#in-kotlin-code)\n    - [in Kotlin Script](#in-kotlin-script)\n      * [blocking api](#blocking-api)\n      * [non blocking api](#non-blocking-api)\n  + [processes](#processes)\n    - [creating and starting processes](#creating-and-starting-processes)\n      * [system process](#system-process)\n      * [kts process](#kts-process)\n    - [multiple calls to processes](#multiple-calls-to-processes)\n  + [pipelines](#pipelines)\n    - [piping overview](#piping-overview)\n      * [piping introduction](#piping-introduction)\n      * [piping grammar](#piping-grammar)\n    - [creating pipeline](#creating-pipeline)\n    - [forking stderr](#forking-stderr)\n    - [lambdas in pipelines](#lambdas-in-pipelines)\n    - [lambdas suitable for piping](#lambdas-suitable-for-piping)\n      * [example](#example)\n  + [detaching](#detaching)\n    - [detaching overview](#detaching-overview)\n    - [detaching process](#detaching-process)\n    - [detaching pipeline](#detaching-pipeline)\n    - [attaching](#attaching)\n  + [daemonizing](#daemonizing)\n  + [environment](#environment)\n    - [system environment](#system-environment)\n    - [shell environment](#shell-environment)\n    - [shell variables](#shell-variables)\n    - [special variables](#special-variables)\n  + [shell commands](#shell-commands)\n    - [implemented shell commands](#implemented-shell-commands)\n    - [shell methods](#shell-methods)\n    - [custom shell commands](#custom-shell-commands)\n    - [custom shell methods](#custom-shell-methods)\n    - [special properties](#special-properties)\n  + [sub shells](#sub-shells)\n    - [creating sub shells](#creating-sub-shells)\n    - [sub shells use cases](#sub-shells-use-cases)\n  + [scripting specific features](#scripting-specific-features)\n    - [dependencies](#dependencies)\n      * [external dependencies](#external-dependencies)\n      * [internal dependencies](#internal-dependencies)\n* [examples](#examples)\n\n## preliminary\nThe library is designed primary for Unix-like operating systems and was tested fully on MacOS.\nWindows support is not planned at the moment.\n\n## how to get Kotlin Shell\n\n\u003e Kotlin Shell is distributed via GitHub Packages.\n\n### for scripting\n[![Maven Central](https://maven-badges.herokuapp.com/maven-central/eu.jrie.jetbrains/kotlin-shell-kts/badge.svg)](https://maven-badges.herokuapp.com/maven-central/eu.jrie.jetbrains/kotlin-shell-kts)\n\nUse `kshell` command for running scripts from command line. To read more about it and download the command go [here](https://github.com/jakubriegel/kshell).\n\nYou can also [download](https://github.com/jakubriegel/kotlin-shell/packages) binaries of `kotlin-shell-kts` to use the script definition in custom way.\n\n### as library\n[![Maven Central](https://maven-badges.herokuapp.com/maven-central/eu.jrie.jetbrains/kotlin-shell-core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/eu.jrie.jetbrains/kotlin-shell-core)\n\n\nGradle:\n```kotlin\nrepositories {\n  dependencies {\n    implementation(\"eu.jrie.jetbrains:kotlin-shell-core:0.2.1\")\n  }\n}\n```\n\nFor more information about using GitHub packages with Gradle go [here](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-gradle-registry#installing-a-package) or to packages section of thi repository.\n\nKotlin Shell features slf4j logging. To use it add logging implementation or NOP logger to turn it off: \n```kotlin\nimplementation(\"org.slf4j:slf4j-nop:1.7.26\")\n```\n\nYou can also [download](https://bintray.com/jakubriegel//kotlin-shell/kotlin-shell-core/_latestVersion) binaries of `kotlin-shell-core` to use the library in any other project.\n\n## how to run the scripts\n### in Kotlin script\nKotlin Shell scripts have `sh.kts` extension.\n\nSome environment variables may be set to customize script execution. Go to the [environment](#environment) section to learn more.\n\n#### kshell command\n##### command line\nTo run the script type:\n```\nkshell script.sh.kts\n```\nRead more and download the command [here](https://github.com/jakubriegel/kshell).\n\n##### shebang\nKotlin Shell scripts support shebang:\n```\n#!/usr/bin/env kshell\n```\n\n#### kotlinc command\nA more low level approach is supported with `kotlinc`:\n\n```\nkotlinc -cp PATH_TO_SHELL_KTS_ALL_JAR -Dkotlin.script.classpath  -script SCRIPT.sh.kts ARGS\n```\n\nexample:\n```\nkotlinc -cp lib/kotlin-shell-kts-all.jar -Dkotlin.script.classpath  -script hello.sh.kts\n```\n### in Kotlin programs\nCalling the `shell` block will provide access to Kotlin Shell API:\n```kotlin\nshell {\n  // code\n}\n```\n\n## usage\n### writing scripts \nKotlin Shell is driven by [kotlinx.io](https://github.com/Kotlin/kotlinx-io) and [kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines). Therefore the API is fully non-blockign and most functions are suspending. To take advantage of that, you need to pass the script as `suspend fun` and `CoroutineScope` as parameters to the suspending `shell` block.\n\n#### in Kotlin code\nWith given scope:\n```kotlin\nshell (\n    scope = myScope\n) {\n    \"echo hello world!\"()\n}\n```\n\nWith new coroutine scope:\n```kotlin\nshell {\n    \"echo hello world!\"()\n}\n```\n\n\n#### in Kotlin Script\n##### blocking api\nThe blocking api features basic shell commands without the need of wrapping it into coroutines calls:\n```kotlin\n\"echo hello world!\".process().run()\n```\nIt can be accessed in Kotlin code as well by using `ScriptingShell` class.\n\n##### non blocking api\nThe `shell` block gives access to full api of `kotlin-shell`. It receives `GlobalScope` as implicit parameter:\n```kotlin\nshell {\n    \"echo hello world!\"()\n}\n```\n\n### processes\n#### creating and starting processes\nBefore starting any process you need to create `ProcessExecutable`. Then you can start it directly or use it in pipeline.\n\n##### system process\nTo start new system process use dsl:\n```kotlin\nval echo = systemProcess {\n    cmd { \"echo\" withArg \"hello\" }\n}\necho()\n```\n\nor extensions:\n```kotlin\nval echo = \"echo hello\".process() \necho()\n```\nor simply: \n```kotlin\n\"echo hello\"() \n```\n\nTo start process from file contents use `File.process()` extension:\n```kotlin\nval process = scriptFile.process(arg1, arg2)\nprocess()\n```\n\nor simply:\n```kotlin\nscriptFile(arg1, arg2)\n```\n\n##### kts process\n_creating virtual KotlinScript processes is not implemented yet_\n\n#### multiple calls to processes\nTo run equivalent process multiple times call `ProcessExecutable.copy()` \n\n### pipelines\nPipelines can operate on processes, lambdas, files, strings, byte packages and streams. \n\n#### piping overview\n##### piping introduction\nEvery executable element in Kotlin Shell receives its own `ExecutionContext`, which consist of `stdin`, `stdout` and `stderr` implemented as `Channels`. In the library channels are used under aliases `ProcessChannel`, `ProcessSendChannel` and `ProcessReceiveChannel` their unit is always `ByteReadPacket`. `Shell` itself is an `ExecutionContext` and provides default channels:\n* `stdin` is always empty and closed `ProcessReceiveChannel`, which effectively acts like `/dev/null`. It  It can be accessed elsewhere by `nullin` member.\n* `stdout` is a rendezvous `ProcessSendChannel`, that passes everything to `System.out`.\n* `stderr` is a reference to `stdout`.\n\nBeside them there is also special member `ProcessSendChannel` called `nullout`, which acts like `/dev/null`. \n\nPipeline elements are connected by `ProcessChannel`s, that override their context's default IO. Only the neccessary streams are overriden, so not piped ones are redirected to the channels, that came with the context. Each element in the pipeline ends its execution after processing the last received packet before receiving close signal from `stdin` channel. \n\nPipelines are logically divided into three parts: `FROM`, `THROUGH` and `TO`. The api is designed to look seamless, but in order to take full advantage of piping it is necessary to distinguish these parts. Every element can emit some output, but doesn't have to. They also shouldn't close they outputs after execution. It is done automatically by piping engine and ensures that channels used by other entities (such as `stdout`) won't be closed.\n\nEvery pipeline starts with single element `FROM` section. It can be `Process`, [lambda](#lambdas-in-pipelines), `File`, `String`, `InputStream`, `ByteReadPacket` or `Channel`. Elements used here receive no input (for processes and lambdas there is `nullin` provided). Then the `THROUGH` or `TO` part occurs. \nPiping `THROUGH` can be performed on `Process` or [lambda](#lambdas-in-pipelines) and can consist of any number of elements. They receive the input simutanously while the producer is going (due to the limitations of `zt-exec` library `SystemProcess` may wait till the end of input) and can emit output as they go. \nEvery pipeline is ended with single element `TO` section. Elements here take input, but do not emit any output. If no `TO` element is provided, the `pipeline` builder will implicitly end the pipeline with `stdout`.\n\n##### piping grammar\nSchematic grammar for piping could look like this:\n```\nPIPELINE -\u003e FROM THROUGH TO\nPIPELINE -\u003e FROM TO\nFROM -\u003e PROCESS | LAMBDA | FILE | STRING | INPUT_STREAM | BYTE_READ_PACKET | PROCESS_SEND_CHANNEL\nTHROUGH -\u003e PROCESS | LAMBDA\nTO -\u003e PROCESS | LAMBDA | FILE | STRING_BUILDER | OUTPUT_STREAM | BYTE_PACKET_BUILDER | PROCESS_RECEIVE_CHANNEL\n```\n\n#### creating pipeline\nTo construct and execute the pipeline use `pipeline` builder:\n```kotlin\npipeline { a pipe b pipe c }\n```\n\nPipeline can be started with `Process`, lambda, `File`, `String`, `ByteReadPacket` or `InputStream`. Once the pipeline is created it cannot be modified.\n\nThe `pipeline` builder takes an optional parameter `mode` of type `ExecutionMode`. It can be used for [detaching](#detaching) or [demonizing](#demonizing) the pipeline. By default it uses `ExecutionMode.ATTACHED`\n```kotlin\npipeline (ExecutionMode.ATTACHED) { a pipe b pipe c }\npipeline (ExecutionMode.DETACHED) { a pipe b pipe c }\npipeline (ExecutionMode.DAEMON) { a pipe b pipe c }\n```\n\nConstructed pipeline can be stored in an object of `Pipeline` type:\n```kotlin\nval p = pipeline { a pipe b }\n```\n\nYou can perform several operiations on it:\n* `Pipeline.join()` joins the pipeline\n* `Pipeline.kill()` kill all elements of the pipeline\n\nAnd access `processes` member, which is a list of all processes in the pipeline.\n\n#### forking stderr\nTo fork `stderr` from process or lambda use `forkErr`:\n```kotlin\npipeline { a pipe (b forkErr { /* fork logic */ }) pipe c }\n```\n\nit redirects elements error stream to given pipeline. \n\nThe builder function receives the new error `ProcessReceiveChannel` as an implicit argument. \nThe function should return new `Pipeline`. If this pipeline wont be ended with `TO`, it will implicitly be appended with `stdout`.\n\nThe fork logic can be stored in a variable:\n```kotlin\nval fork = pipelineFork { it pipe filter pipe file }\npipeline { a forkErr fork }\n```\n\nThe fork belongs to process executable or lambda itself so it can be used outside pipeline as well:\n```kotlin\nval process = \"cmd arg\".process() forkErr { /* fork */ }\nprocess()\n```\n\n```kotlin\nval lambda = stringLambda { /* lambda */ } forkErr { /* fork */ }\npipeline { lambda pipe { /* ... */} }\n```\n\nAs a shorthand it is possible to fork error directly to given channel:\n```kotlin\nval channel: ProcessChannel = Channel()\nval b = a forkErr channel\n```\n\n\n#### lambdas in pipelines\nBasic lambda structure for piping is `PipelineContextLambda`:\n```kotlin\nsuspend (ExecutionContext) -\u003e Unit\n```\nIt takes context which consists of `stdin`, `stdout` and `stderr` channels. It can receive content immediately after it was emitted by the producer, as well as its consumer can receive sent content simultaneously. \n\nThe end of input is signalized with closed `stdin`. `PipelineContextLambda` shouldn't close outputs after execution.\n\n#### lambdas suitable for piping\nThere are several wrappers for `PipelineContextLambda`, that can make piping easier. Most of them follow the template `(stdin) -\u003e Pair\u003cstdout, stderr\u003e`\n\nname | definition | builder\n--- | --- | --- \n`PipelineContextLambda` | suspend (ExecutionContext) -\u003e Unit | contextLambda { }\n`PipelinePacketLambda` | suspend (ByteReadPacket) -\u003e Pair\u003cByteReadPacket, ByteReadPacket\u003e | packetLambda { }\n`PipelineByteArrayLambda` | suspend (ByteArray) -\u003e Pair\u003cByteArray, ByteArray\u003e | byteArrayLambda { } \n`PipelineStringLambda` | suspend (String) -\u003e Pair\u003cString, String\u003e | stringLambda { /* code */ }\n`PipelineStreamLambda` | suspend (InputStream, OutputStream, OutputStream) -\u003e Unit | streamLambda { }\n\n##### example\n```kotlin\nshell {\n    val upper = stringLambda { line -\u003e\n        line.toUpperCase() to \"\"\n    }\n    pipeline { \"cat file\".process() pipe upper pipe file(\"result\") }\n}\n```\n\n### detaching\n#### detaching overview\nDetached process or pipeline is being executed asynchronous to the shell. It can be attached or awaited at any time. Also all of not-ended detached jobs will be awaited after the end of the script before finishing `shell` block.\n\n#### detaching process\nTo detach process use `detach()` function:\n```kotlin\nval echo = \"echo hello world!\".process()\ndetach(echo)\n``` \n\nTo join process use `Process.join()` method:\n```kotlin\nprocess.join()\n```\n\nYou can perform these operations also on multiple processes:\n```kotlin\ndetach(p1, p2, p2)\n```\n```kotlin\nawait(p1, p2, p3)\n```\n\nTo join all processes use `joinAll()`.\n\nTo access detached processes use `detachedProcesses` member. It stores list of pair of detached job id to process\n\n#### detaching pipeline\nTo detach pipeline use `detach()` builder:\n```kotlin\ndetach { p1 pipe p2 pipe p3 }\n```\n\nor `pipeline()` with correct mode:\n```kotlin\npipeline (ExecutionMode.DETACHED) { p1 pipe p2 pipe p3 }\n```\n\nTo join pipeline call `Pipeline.join()`:\n```kotlin\nval pipeline = detach { p1 pipe p2 pipe p3 }\npipeline.join()\n```\n\nTo access detached processes use `detachedPipelines` member. It stores list of pair of detached job id to pipeline\n\n#### attaching\nTo attach detached job (process or pipeline) use `fg()`:\n* `fg(Int)` accepting detached job id. By default it will use `1` as id.\n* `fg(Process)` accepting detached process\n* `fg(Pipeline)` accepting detached pipeline\n\nTo join all detached jobs call `joinDetached()`\n\n### daemonizing\n\u003e At the current stage demonizing processes and pipelines is implemented in very unstable and experimental way. \n\u003e \n\u003e Though it should not be used. \n\n### environment\nEnvironment in Kotlin Shell is divided into two parts `shell environment` and `shell variables`. The environment from system is also copied.\n\nTo access the environment call:\n* `environment` list or `env` command for `shell environment`\n* `variables` list for `shell variables`\n* `shellEnv` or `set` command for combined environment\n* `systemEnv` for the environment inherited from system\n\n#### system environment\n`system environment` is copied to `shell environment` at its creation. To access system environment any time call `systemEnv`\n\n#### shell environment\n`shell environment` is copied to `Shell` from the system. It can be modified and is copied to sub shells.\n\nTo set environment use `export`:\n```kotlin\nexport(\"KEY\" to \"VALUE\")\n```\n\nTo make it read-only add `readonly`:\n```kotlin\nreadonly export(\"KEY\" to \"VALUE\")\n```\n\nTo print environment variable use `env`:\n```kotlin\nenv(\"KEY\")\n```\n\nTo remove use `unset`:\n```kotlin\nunset(\"key\")\n```\n\n#### shell variables\n`shell variables` are empty by default. They can be modified and __are not__ copied to sub shells   \n\nTo set variable use `variable`:\n```kotlin\nvariable(\"KEY\" to \"VALUE\")\n``` \n\nTo make it read-only add `readonly`:\n```kotlin\nreadonly variable(\"KEY\" to \"VALUE\")\n```\n\nTo print shell variable use `env`:\n```kotlin\nenv(\"KEY\")\n```\n\nTo remove variable use `unset`:\n```kotlin\nunset(\"key\")\n```\n\n#### special variables\nKotlin Shell uses some special variables for customisation of execution. \nThey can be set explicitly by `shell` builders or can be inherited from system. \nIf any of these will not be set, default values will be used.\n\nvariable | type | usage | default value\n--- | --- | --- | ---\n`SYSTEM_PROCESS_INPUT_STREAM_BUFFER_SIZE` | `Int` | size of `SystemProcessInputStream` buffer | 16\n`PIPELINE_RW_PACKET_SIZE` | `Long` | maximal size of packets used in piping | 16\n`PIPELINE_CHANNEL_BUFFER_SIZE` | `Int` | size of `ProcessChannel`s used in piping  | 16\n`REDIRECT_SYSTEM_OUT` | `YES`/`NO` | Specifies weather `System.out` should be bypassed with `Shell.stdout`. As a result it will synchronize stdlib `print()` and `println()` with `shell` outputs | YES\n\n\n\n### shell commands\nKotlin Shell implements some of the most popular shell commands with additions of special methods and properties.\n\nTo call the command use `invoke()`:\n```kotlin\ncmd()\n```\nthen its output will be processed to `stdout`.\n\nTo pipe the command put simply put it in the pipeline:\n```kotlin\npipeline { cmd pipe process }\n```\n\n#### implemented shell commands\n* `\u0026` as `detach`\n* `cd` with `cd(up)` for `cd ..` and `cd(pre)` for `cd -`\n* `env`\n* `exit` as `return@shell`\n* `export`\n* `fg`\n* `jobs`\n* `mkdir`\n* `print` and `echo` as `print()`/`println()`\n* `ps`\n* `readonly`\n* `set`\n* `unset`\n* setting shell variable as `variable`\n\n#### shell methods\n`Shell` member functions provide easy ways for performing popular shell tasks:\n* `file()` - gets or creates file relative to current directory\n\n#### custom shell commands\nTo implement custom shell command create extension member of Shell class and override its getter:\n```kotlin\nval Shell.cmd: ShellCommand\n    get() = command {\n        /* command implementation returning String */\n    }\n```\n\nsuch command can be declared outside `shell` block and be used as [dependency](#internal-dependencies).\n\n#### custom shell methods \nTo implement custom shell method use the basic function template:\n```kotlin\nsuspend fun Shell.() -\u003e T\n```\n\nwhere `T` is desired return type or `Unit`. Such functions can be declared outside `shell` block and be used as [dependency](#internal-dependencies).\n\n#### special properties\n`Shell` members provide easy Kotlin-like access to popular parameters:\n* `detachedPipelines`\n* `detachedProcesses`\n* `directory`\n* `environment`\n* `nullin`\n* `nullout`\n* `processes`\n* `shellEnv`\n* `systemEnv`\n* `variables`\n\n### sub shells\n#### creating sub shells\nTo create sub shell use `shell` block:\n```koltin\nshell {\n    /* code */\n    shell {\n        /* code */\n    }\n}\n```\n\nBy default sub shell will inherit environment, directory, IO streams and constants. \nYou can explicitly specify shell variables and directory to use:\n```kotlin\nshell {\n    shell (\n        vars = mapOfVariables,\n        dir = directoryAsFile\n    ) {\n        /* code */\n    }\n}\n```\n\nSub shells suspend execution of the parent shell.\n\n#### sub shells use cases \nSub shell can be used to provide custom environment for commands:\n```kotlin\nshell {\n  export(\"KEY\" to \"ONE\")\n  shell (\n    vars = mapOf(\"KEY\" to \"TWO\")\n  ) {\n    \"echo ${env(\"KEY\")} // TWO\n  }\n  \n  // rest of the script\n}\n```\n\nOr to temporarly change the directory:\n```kotlin\nshell {\n  \"echo ${env(\"PWD\")} // ../dir\n\n  shell (\n    dir = file(\"bin\")\n  ) {\n    \"echo ${env(\"PWD\")} // ../dir/bin\n  }\n  \n  // rest of the script\n}\n```\n\n### scripting specific features\n#### dependencies\nKotlin Shell scripts support external and internal dependencies. The mechanism from `kotlin-main-kts` is being used. Learn more about it in [KEEP](https://github.com/Kotlin/KEEP/blob/master/proposals/scripting-support.md) and [blog post](https://blog.jetbrains.com/kotlin/2018/09/kotlin-1-3-rc-is-here-migrate-your-coroutines/#scripting).\n\n##### external dependencies\nExternal dependencies from maven repositories can be added via `@file:Repository` `@file:DependsOn` annotation: \n```kotlin\n@file:Repository(\"MAVEN_REPOSITORY_URL\")\n@file:DependsOn(\"GROUP:PACKAGE:VERSION\")\n```\nthen they can be imported with standard `import` statement.\n\n##### internal dependencies\nTo import something from local file use `@file:Import`:\n```kotlin\n@file:Import(\"SCRIPT.sh.kts\")\n```\nthen they can be imported with standatd `import` statement.\n\n\n## examples\nExamples on writing Kotlin shell scripts can be found in the [examples repository](https://github.com/jakubriegel/kotlin-shell-examples).\n\nA good source of detailed examples are also integration tests in this repository.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjakubriegel%2Fkotlin-shell","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjakubriegel%2Fkotlin-shell","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjakubriegel%2Fkotlin-shell/lists"}