---
myst:
  html_meta:
    "keywords": "tutorial, declarative, shell, environment, developer, nix, nixpkgs"
---

(declarative-reproducible-envs)=
# `shell.nix`를 사용한 선언적 셸 환경

```{contributors}
:authors: domenkozar, zmitchell
:editors: fricklerhandwerk
```
## 개요

선언적 셸 환경을 사용하면 다음과 같은 일을 할 수 있습니다:

- 환경 활성화 시 bash 명령을 자동으로 실행합니다
- 환경 변수를 자동으로 설정합니다
- 환경 정의를 버전 관리하에 두고 다른 머신에서 재현합니다

### 무엇을 배우게 됩니까?

{ref}`ad-hoc-envs` 튜토리얼에서는 `nix-shell -p`를 사용하여 셸 환경을 명령적으로 만드는 방법을 배웠습니다. 이 방법은 도구를 영구적으로 설치하지 않고 빠르게 사용하고 싶을 때 매우 유용합니다. 또한 이전에 사용한 것과 동일한 환경을 다시 만들기 위해, Git 커밋을 인수로 사용하여 특정 Nixpkgs 리비전으로 해당 명령을 실행하는 방법도 배웠습니다.

이 튜토리얼에서는 {term}`Nix 파일 <Nix file>`에 작성한 선언적 설정으로 재현 가능한 셸 환경을 만드는 방법을 살펴보겠습니다. 이 파일을 누구와도 공유하여 다른 머신에서 동일한 환경을 다시 만들 수 있습니다.

### 얼마나 걸립니까?

30분

### 무엇이 필요합니까?

- Unix 셸에 대한 익숙함
- [Nix 언어](reading-nix-language)에 대한 기초적인 이해

## 임시 셸 진입하기

`cowsay`와 `lolcat`을 사용할 수 있는 환경이 필요하다고 가정해 봅시다. 이를 달성하는 가장 간단한 방법은 `nix-shell -p` 명령을 사용하는 것입니다:

```
$ nix-shell -p cowsay lolcat
```

이 명령은 작동하지만 여러 가지 단점이 있습니다:
- 셸에 진입할 때마다 `-p cowsay lolcat`을 입력해야 합니다.
- 셸 환경을 더 이상 (편리하게) 사용자 지정할 수 없습니다.

더 나은 해결책은 `shell.nix` 파일로 셸 환경을 만드는 것입니다.

## 기본적인 `shell.nix` 파일

다음 내용으로 `shell.nix`라는 파일을 만드십시오:

{lineno-start=1}
```nix
let
  nixpkgs = fetchTarball "https://github.com/NixOS/nixpkgs/tarball/nixos-24.05";
  pkgs = import nixpkgs { config = {}; overlays = []; };
in

pkgs.mkShellNoCC {
  packages = with pkgs; [
    cowsay
    lolcat
  ];
}
```

::::{dropdown} 자세한 설명
[릴리스 브랜치에 고정된 Nixpkgs](<ref-pinning-nixpkgs>) 버전을 사용합니다. [](ad-hoc-envs) 튜토리얼을 따라 했고 모든 의존성을 다시 다운로드하고 싶지 않다면, [](towards-reproducibility) 섹션에서와 정확히 동일한 리비전을 지정하십시오:

{lineno-start=1 emphasize-lines="2"}
```nix
let
  nixpkgs = fetchTarball "https://github.com/NixOS/nixpkgs/tarball/2a601aafdc5605a5133a2ca506a34a3a73377247";
  pkgs = import nixpkgs { config = {}; overlays = []; };
in
```

[전역 설정](https://nixos.org/manual/nixpkgs/stable/#chap-packageconfig)에 의해 의도치 않게 오버라이드되는 것을 방지하기 위해 `config`와 `overlays`를 명시적으로 설정합니다.

`mkShellNoCC`는 속성 집합을 인수로 받는 함수입니다. 여기서는 `pkgs` 속성 집합의 두 항목을 담은 목록을 `packages` 속성으로 전달합니다.

:::{Dropdown} `mkShell`에 대한 참고 사항

`nix-shell`과 `mkShell`은 원래 Make나 GCC 같은 [패키지 빌드를 디버깅하는 데 필요한 도구](https://nixos.org/manual/nixpkgs/stable/#sec-tools-of-stdenv)를 담은 셸 환경을 구성하는 방법으로 고안되었습니다. 나중에야 다른 목적의 임시 환경을 만드는 일반적인 방법으로 널리 쓰이게 되었습니다. `mkShellNoCC`는 이러한 환경을 만들되 컴파일러 툴체인은 포함하지 않는 함수입니다.

패키지를 `buildInputs`나 `nativeBuildInputs` 속성에 대신 추가하는 `mkShell` 또는 `mkShellNoCC` 예제를 볼 수도 있습니다. `mkShellNoCC`는 [`mkDerivation`을 감싼 래퍼](https://nixos.org/manual/nixpkgs/stable/#sec-pkgs-mkShell)이므로 `buildInputs`나 `nativeBuildInputs` 같은 `mkDerivation`과 동일한 인자를 받습니다. `mkShellNoCC`에 전달하는 `packages` 속성 인자는 단순히 `nativeBuildInputs`의 별칭입니다.
:::
::::

`shell.nix`와 같은 디렉터리에서 `nix-shell`을 실행하여 환경에 진입하십시오:

:::{note}
이 파일에 대해 `nix-shell`을 처음 실행하면 모든 의존성을 내려받느라 시간이 걸릴 수 있습니다.
:::

```console
$ nix-shell
[nix-shell]$ cowsay hello | lolcat
```

`nix-shell`은 기본적으로 현재 디렉터리에서 `shell.nix`라는 파일을 찾아 이 파일의 Nix 표현식으로부터 셸 환경을 빌드합니다. `packages` 속성에 정의된 패키지는 `$PATH`에서 사용할 수 있습니다.

## 환경 변수

셸 환경에 진입할 때 특정 환경 변수를 자동으로 내보내고 싶을 수 있습니다.

셸 환경에서 사용할 수 있도록 `GREETING`을 설정하십시오:

```diff
 let
   nixpkgs = fetchTarball "https://github.com/NixOS/nixpkgs/tarball/nixos-24.05";
   pkgs = import nixpkgs { config = {}; overlays = []; };
 in

 pkgs.mkShellNoCC {
   packages = with pkgs; [
     cowsay
     lolcat
   ];

+  GREETING = "Hello, Nix!";
 }
```

`mkShellNoCC`에 전달된 속성 이름 중 달리 예약되지 않았고 문자열로 변환할 수 있는 값을 가진 속성은 모두 환경 변수가 됩니다.

직접 해 보십시오. `exit`를 입력하거나 `Ctrl`+`D`를 눌러 셸을 종료한 다음, `nix-shell`로 다시 시작하십시오.

```console
[nix-shell]$ echo $GREETING
```

:::{warning}
일부 변수는 위에서 설명한 방식으로 설정할 수 없도록 보호되어 있습니다.

예를 들어, 대부분의 셸에서 셸 프롬프트 형식은 `PS1` 환경 변수로 설정되지만, `nix-shell`이 이미 기본값을 설정하므로 인수로 전달한 속성 집합에 설정된 `PS1` 속성은 무시됩니다.

이렇게 보호된 환경 변수를 오버라이드해야 한다면 다음 절에서 설명하는 대로 `shellHook` 속성을 사용하십시오.
:::

## 시작 명령

대화형 셸 환경에 진입하기 전에 몇 가지 셸 명령을 실행하고 싶을 수 있습니다. 이러한 명령은 `mkShellNoCC`에 전달하는 `shellHook` 속성에 넣을 수 있습니다.

알록달록한 인사말을 출력하도록 `shellHook`을 설정하십시오:

```diff
 let
   nixpkgs = fetchTarball "https://github.com/NixOS/nixpkgs/tarball/nixos-24.05";
   pkgs = import nixpkgs { config = {}; overlays = []; };
 in

 pkgs.mkShellNoCC {
   packages = with pkgs; [
     cowsay
     lolcat
   ];

   GREETING = "Hello, Nix!";
+
+  shellHook = ''
+    echo $GREETING | cowsay | lolcat
+  '';
 }
```

다시 해 보십시오. `exit`를 입력하거나 `Ctrl`+`D`를 눌러 셸을 종료한 다음, `nix-shell`로 다시 시작하여 결과를 확인하십시오.

## 참고 자료

- [`mkShell` 문서](https://nixos.org/manual/nixpkgs/stable/#sec-pkgs-mkShell)
- Nixpkgs [셸 함수 및 유틸리티](https://nixos.org/manual/nixpkgs/stable/#ssec-stdenv-functions) 문서
- [`nix-shell` 문서](https://nix.dev/manual/nix/stable/command-ref/nix-shell)

## 다음 단계

- [](reading-nix-language)
- [](automatic-direnv)
- [](../../guides/recipes/sharing-dependencies.md)
- [](../../guides/recipes/dependency-management.md)
