(ad-hoc-envs)=

# 임시 셸 환경

```{contributors}
:authors: domenkozar
:editors: fricklerhandwerk
```

Nix 셸 환경에서는 Nix로 패키징된 어떤 프로그램이든 영구적으로 설치하지 않고도 바로 사용할 수 있습니다.

이러한 셸을 실행하는 명령을 다른 사람과 공유할 수도 있으며, 이 명령은 모든 Linux 배포판, WSL, macOS[^1]에서 동작합니다.

[^1]: 모든 패키지가 Linux와 macOS를 모두 지원하는 것은 아닙니다. 특히 그래픽 프로그램은 지원 여부가 다를 수 있습니다.

## 셸 환경 만들기

{ref}`Nix를 설치 <install-nix>`하고 나면, Nix를 사용하여 원하는 프로그램이 포함된 새 *셸 환경*을 만들 수 있습니다.

이 절에서는 여러분의 컴퓨터에 아마 설치되어 있지 않을 `cowsay`와 `lolcat`이라는 두 가지 특이한 프로그램을 실행해 봅니다.

```shell-session
$ cowsay no can do
The program ‘cowsay’ is currently not installed.

$ echo no chance | lolcat
The program ‘lolcat’ is currently not installed.
```

`nix-shell`에 `-p` (`--packages`) 옵션을 사용하여 `cowsay`와 `lolcat` 패키지가 필요하다고 지정하십시오.

:::{note}
이 패키지들로 `nix-shell`을 처음 실행할 때는 모든 의존성을 다운로드하느라 시간이 걸릴 수 있습니다.
:::

```shell-session
$ nix-shell -p cowsay lolcat
these 3 derivations will be built:
  /nix/store/zx1j8gchgwzfjn7sr4r8yxb7a0afkjdg-builder.pl.drv
  /nix/store/h9sbaa2k8ivnihw2czhl5b58k0f7fsfh-lolcat-100.0.1.drv
  ...

[nix-shell:~]$
```

Nix 셸 안에서는 이 패키지들이 제공하는 프로그램을 사용할 수 있습니다.

```shell-session
[nix-shell:~]$ cowsay Hello, Nix! | lolcat
```

`exit`를 입력하거나 `CTRL-D`를 눌러 셸을 종료하면 해당 프로그램은 더 이상 사용할 수 없습니다.

```shell-session
[nix-shell:~]$ exit
exit

$ cowsay no more
The program ‘cowsay’ is currently not installed.

$ echo all gone | lolcat
The program ‘lolcat’ is currently not installed.
```

## 프로그램을 한 번만 실행하기

어떤 프로그램이든 직접 실행하면 더욱 빠르게 사용할 수 있습니다.

```console
$ nix-shell -p cowsay --run "cowsay Nix"
```

명령이 프로그램 이름만으로 이루어져 있다면 따옴표가 필요하지 않습니다.

```console
$ nix-shell -p hello --run hello
```

## 패키지 검색하기

셸 환경에는 무엇을 넣을 수 있습니까? 떠오르는 프로그램이라면 아마 이미 Nix 패키지로 존재할 것입니다.

:::{tip}
[search.nixos.org](https://search.nixos.org/packages)에 실행하려는 프로그램 이름을 입력하여 그 프로그램을 제공하는 패키지를 찾으십시오.
:::

다음 예제를 위해 아래 프로그램들의 패키지 이름을 찾으십시오.

- `git`
- `nvim`
- `npm`

검색 결과에서 각 항목은 패키지 이름을 보여 주며, 세부 정보에는 사용할 수 있는 프로그램이 나열되어 있습니다.[^2]

[^2]: 패키지 이름은 프로그램 이름과 같지 않습니다. 많은 패키지가 여러 프로그램을 제공하며, 라이브러리인 경우에는 프로그램을 전혀 제공하지 않기도 합니다. 프로그램을 정확히 하나만 제공하는 패키지라도 패키지 이름과 프로그램 이름이 반드시 같은 것은 아닙니다.

(run-any-program)=
## 여러 프로그램을 자유롭게 조합하여 실행하기

패키지 이름을 알고 나면 해당 패키지로 셸을 시작할 수 있습니다. `-p` (`--packages`) 인수에는 여러 패키지 이름을 지정할 수 있습니다.

`git`, `nvim`, `npm`을 제공하는 패키지로 Nix 셸을 시작하십시오. 이번에도 처음 실행할 때는 모든 의존성을 다운로드하느라 시간이 걸릴 수 있습니다.

```shell-session
$ nix-shell -p git neovim nodejs
these 9 derivations will be built:
  /nix/store/7gz8jyn99kw4k74bgm4qp6z487l5ap06-packdir-start.drv
  /nix/store/d6fkgxc3b04m85wrhg6j0l5y0ray82l7-packdir-opt.drv
  /nix/store/da6njv7r0zzc2n54n2j54g2a5sbi4a5i-manifest.vim.drv
  /nix/store/zs4jb2ybr4rcyzwq0dagg9rlhlc368h6-builder.pl.drv
  /nix/store/g8sl2xnsshfrz9f39ki94k8p15vp3xd7-vim-pack-dir.drv
  /nix/store/jmxkg8b1psk52awsvfziy9nq6dwmxmjp-luajit-2.1.0-2022-10-04-env.drv
  /nix/store/kn83q8yk6ds74zgyklrjhvv5wkv5wmch-python3-3.10.9-env.drv
  /nix/store/m445wn3vizcgg7syna2cdkkws3kk1gq8-neovim-ruby-env.drv
  /nix/store/r2wa882mw99c311a4my7hcis9lq3kp3v-neovim-0.8.1.drv
these 151 paths will be fetched (186.43 MiB download, 1018.20 MiB unpacked):
  /nix/store/046zxlxhq4srm3ggafkymx794bn1jksc-bzip2-1.0.8
  /nix/store/0p1jxcb7b4p8jhhlf8qnjc4cqwy89460-unibilium-2.1.1
  /nix/store/0q4fpnqmg8liqraj7zidylcyd062f6z0-perl5.36.0-URI-5.05
  ...

[nix-shell:~]$
```

(check-package-version)=
### 패키지 버전 확인하기

컴퓨터에 이 프로그램 중 일부가 이미 설치되어 있었더라도, Nix가 제공하는 특정 버전을 사용하고 있는지 확인하십시오.

```shell-session
[nix-shell:~]$ which git
/nix/store/3cdi52xh6lk3h1fb51jkxs3p561p37wg-git-2.38.3/bin/git

[nix-shell:~]$ git --version
git version 2.38.3

[nix-shell:~]$ which nvim
/nix/store/ynskzgkf07lmrrs3cl2kzr9ah487lwab-neovim-0.8.1/bin/nvim

[nix-shell:~]$ nvim --version | head -1
NVIM v0.8.1

[nix-shell:~]$ which npm
/nix/store/q12w83z0i5pi1y0m6am7qmw1r73228sh-nodejs-18.12.1/bin/npm

[nix-shell:~]$ npm --version
8.19.2
```

## 중첩 셸 세션

추가 프로그램이 일시적으로 필요하다면 중첩된 Nix 셸을 실행할 수 있습니다. 지정한 패키지가 제공하는 프로그램이 현재 환경에 추가됩니다.

```shell-session
[nix-shell:~]$ nix-shell -p python3
this path will be fetched (11.42 MiB download, 62.64 MiB unpacked):
  /nix/store/pwy30a7siqrkki9r7xd1lksyv9fg4l1r-python3-3.10.11
copying path '/nix/store/pwy30a7siqrkki9r7xd1lksyv9fg4l1r-python3-3.10.11' from 'https://cache.nixos.org'...

[nix-shell:~]$ python --version
Python 3.10.11
```

이전 환경으로 돌아가려면 평소처럼 셸을 종료하십시오.

(towards-reproducibility)=
## 재현성을 향하여

이러한 셸 환경은 매우 편리하지만, 지금까지의 예제는 아직 재현 가능하지 않습니다. 다른 컴퓨터에서 이 명령을 실행하면, 그 컴퓨터에 Nix가 언제 설치되었는지에 따라 다른 버전의 패키지를 가져올 수 있습니다.

재현 가능하다는 것은 무엇을 의미합니까? 완전히 재현 가능한 예제는 명령을 언제 어디서 실행하든 정확히 같은 결과를 냅니다. 제공되는 환경은 매번 동일합니다.

다음 예제는 완전히 재현 가능한 환경을 만듭니다. 언제 어디서든 이 예제를 실행하여 정확히 같은 버전의 `git`을 얻을 수 있습니다.

```shell-session
$ nix-shell -p git --run "git --version" --pure -I nixpkgs=https://github.com/NixOS/nixpkgs/tarball/2a601aafdc5605a5133a2ca506a34a3a73377247
...
git version 2.33.1
```

여기서는 세 가지 일이 일어납니다:

1. `--run`은 Nix가 만든 환경 안에서 주어진 [Bash 명령](https://www.gnu.org/software/bash/manual/bash.html#Shell-Commands)을 실행하고, 실행이 끝나면 종료합니다.

   컴퓨터에 설치되어 있지 않은 프로그램을 빠르게 실행하고 싶을 때마다 `nix-shell`과 함께 이 옵션을 사용할 수 있습니다.

2. `--pure`는 셸을 실행할 때 시스템에 설정된 대부분의 환경 변수를 버립니다.

   즉, 해당 셸 안에서는 Nix가 제공하는 `git`만 사용할 수 있습니다. 이는 예제와 같은 간단한 한 줄짜리 명령에 유용합니다. 하지만 개발하는 동안에는 대개 편집기와 기타 도구를 곁에 두고 싶을 것입니다. 따라서 개발 환경에서는 `--pure`를 생략하고, 추가적인 격리가 필요할 때에만 붙이기를 권장합니다.

3. `-I`는 패키지 선언의 출처로 무엇을 사용할지 결정합니다.

   여기서는 [`nixpkgs`의 특정 Git 리비전](https://github.com/NixOS/nixpkgs/tree/2a601aafdc5605a5133a2ca506a34a3a73377247)을 지정하여, 해당 컬렉션에서 어떤 버전의 패키지가 사용될지 의심의 여지가 없도록 했습니다.


## 참고 자료

- [Nix 매뉴얼: `nix-shell`](https://nix.dev/manual/nix/stable/command-ref/nix-shell) (또는 `man nix-shell` 실행)
- [Nix 매뉴얼: `-I` 옵션](https://nix.dev/manual/nix/stable/command-ref/opt-common.html#opt-I)

## 다음 단계

- {ref}`reproducible-scripts` – 재현 가능한 스크립트에 Nix 사용하기
- {ref}`reading-nix-language` – 패키지와 설정을 선언하는 데 사용되는 Nix 언어 읽는 법 배우기
- {ref}`declarative-reproducible-envs` – 선언적 설정 파일로 재현 가능한 셸 환경 만들기
- {ref}`pinning-nixpkgs` – 패키지 소스의 정확한 버전을 지정하는 여러 방법 배우기

이제 Nix를 충분히 사용해 보셨다면, 예제를 실행하면서 내려받은 여러 버전의 프로그램이 차지하고 있는 디스크 공간을 확보할 수 있습니다:

```shell-session
$ nix-collect-garbage
```
