이 글은 제가 JAVA 명령어 동작을 확인하는 과정에서 발생한 궁금증과 오해를 풀어내고 있습니다.
적절한 이해를 위해 간단한 배경지식을 설명하고, 궁금증을 해소하는 과정으로 이어집니다.
리눅스 명령어는 어떻게 실행될까?
터미널에 입력하는 대부분의 명령어들(ls, cp, chmod, tail..)은 전부 실행파일(binary)입니다.
이러한 실행 파일은 보통 /bin, /usr/bin 같은 특정 폴더에 존재합니다.
생각해보면, ls 명령어는 /bin 폴더에 위치하는데요, /bin 경로에 위치한 ls 파일을 실행하려면 /bin/ls 라고 사용해야 하는 것 아닐까요?
어째서 ls 만 쳐도 정상적으로 실행이 되는 걸까요?
그 이유는 PATH라는 환경변수에 이 폴더들이 등록되어 있기 때문입니다.
PATH란 무엇인가?
PATH 환경변수는 명령어를 실행할 때 "어느 폴더안에서 그 실행파일을 찾을지"를 알려주는 "폴더 경로의 모음집" 입니다.
echo $PATH
/opt/homebrew/bin:/opt/homebrew/sbin:
/Library/Frameworks/Python.framework/Versions/3.11/bin:
/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:
/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system
위와 같이 :(콜론)을 기준으로 폴더를 구분하여, 맨 처음 폴더부터 순차적으로 명령어(ls)와 일치하는 실행파일(ls)를 찾습니다.
ls를 쳤을 경우 다음과 같은 흐름으로 ls 실행파일을 찾습니다.
1. /opt/homebrew/bin에서 ls 실행파일 탐색, 없음 -> 다음 폴더 탐색
2. /opt/homebrew/sbin에서 ls 실행파일 탐색, 없음 -> 다음 폴더 탐색
3. ...
4. /bin에서 ls 실행파일 탐색 -> 존재! 실행
이런 구조로 인해 /bin/ls같은 전체 경로를 쓰지 않아도 명령어를 사용할 수 있게 되는 거죠.
Java도 실행파일이다.
java 역시 마찬가지입니다.
java, javac, javadoc 같은 명령어들도 JDK 폴더 내 bin/ 디렉토리에 포함된 실행파일입니다.
java 설치 시 자동으로 관련 파일들이 설정되어 별도의 경로 표시 없이 사용할 수 있게 됩니다.
어라, 근데 왜 다르지?
위 작동과정을 확인하고자 탐구해봤습니다.
제 환경의 경우 MAC OS이고, 과거에 제가 직접 PATH 환경변수에 jdk 17 경로를 추가해놨었습니다.(문제의 시발점)
따라서 아래와 같이 PATH 환경변수에서 jdk 경로를 확인할 수 있었죠.
❯ echo $PATH
/Library/Java/JavaVirtualMachines/jdk-21.0.2.jdk/Contents/Home/bin:
/opt/homebrew/bin:/opt/homebrew/sbin:
...
그리고 이 경로를 통해 java 실행파일을 찾아낸다고 생각했습니다.
그런데, 제가 알기론 JAVA_HOME 환경변수의 JDK 경로만 변경해도 JDK 버전이 변경되는 것으로 알고 있었습니다.
JAVA_HOME 환경변수 변경만으로 JDK 버전이 변경되려면, PATH에 등록된 JDK 경로도 변경되어야 하는 것이 아닐까요?
그런데 그게 가능할까요? 제 생각으로는 불가능해보입니다.
뭔가 이상했습니다.
검색해보니, JDK 경로를 PATH에 등록하지 않아도 된다는 내용을 보았고, PATH에 등록했던 JDK 경로를 삭제한 후, java 명령어를 실행해봤습니다.
제가 이해한 바로는 java 명령어가 실행될 수 없었습니다. java 실행파일이 PATH 경로에 없었으니까요.
그런데 놀랍게도 실행이 됩니다.
PATH에 JDK 경로를 직접 입력하지 않아도 된다
저는 PATH에 직접 JDK 경로가 등록되어 관리된다고 생각하고 있었습니다.
그래야 적절한 JDK 버전의 실행파일이 실행될테니까요.(다른 사람의 정보를 맹목적으로 믿은 탓도 있습니다..)
사실은,
리눅스의 경우 /usr/bin/java의 심볼릭 링크가 JDK 경로와 연결되어 있고,
MAC의 경우 /usr/bin/java 실행파일을 통해 동적으로 JDK 경로가 연결됩니다.
따라서 java 실행파일은 이미 /usr/bin/ 폴더에 존재하여 따로 설정해주지 않아도 되는 것이었습니다.
(macOS의 경우 다음과 같은 구조로 java가 실행된다고 합니다:)
1. /usr/bin/java 실행파일은 JAVA_HOME 환경변수를 참고해서 해당 JDK 실행파일을 불러오는 역할을 합니다.
2. JAVA_HOME이 jdk 17 경로로 설정되어 있다면, JAVA_HOME의 환경변수를 참조하여 jdk 17의 java 실행파일이 실행되는 것입니다.
그림으로 보면 아래와 같습니다:
글을 정리하면 다음과 같습니다.
1. 명령어도 하나의 실행파일이다.
2. 명령어를 전체경로 없이 실행할 수 있는 것은, PATH 에서 적절한 파일을 찾아주기 때문이다.
3. java 명령어는 /usr/bin/java 실행파일로 실행된다.(동작 구조는 운영체제별로 상이함)
실제 동작을 확인하는 과정에서 제가 알고있던 이해관계와 충돌하였고,
그 충돌을 풀어내는 과정에서 제가 잘못 알았던 점을 이해하고, 문제를 명확하게 이해하고 해결할 수 있었습니다.
'트러블 슈팅' 카테고리의 다른 글
hibernate가 기존 DB 테이블을 재생성하는 문제 (0) | 2024.08.05 |
---|---|
JPA Entity 매핑 관련 오류(java.sql.SQLNonTransientConnectionException) (0) | 2024.05.27 |
DB 연동을 위한 도커 경로 설정 문제 (1) | 2024.05.27 |
Docker build context와 파일 인식 (0) | 2024.05.13 |
[Spring webFlux] Unable to load io.netty.resolver.dns.macos ... 오류 (0) | 2024.03.28 |