terminal 105: PATH and environment variables terminal 105: PATH และตัวแปรแวดล้อม
use PATH as your first environment variable, then use `echo $PATH`, `which`, and `export` to understand how your shell finds commands and why a fix can disappear in a new window ใช้ PATH เป็นตัวแปรแวดล้อมตัวแรกของคุณ แล้วใช้ `echo $PATH`, `which`, และ `export` เพื่อเข้าใจว่า shell หาคำสั่งเจอได้อย่างไร และทำไมวิธีแก้บางอย่างถึงหายไปเมื่อเปิดหน้าต่างใหม่
in terminal 104 you saw the annoying version of the problem:
- the tool exists
- the install worked
- and the shell still says “command not found”
105 is where that stops feeling random.
the name for the missing mental model is PATH.
PATH is just a list of folders your shell searches when you type a command name like rg, git, or python3.
in this lesson, “environment variables” mostly means one important example: PATH. that is intentional. you do not need a full survey yet. you need one variable that explains a lot of real beginner pain immediately.
once you understand that search order, a lot of terminal confusion collapses into three simple questions:
- does the file exist?
- is its folder in
PATH? - if more than one copy exists, which one wins?
what you’ll know by the end
- what
PATHis in plain language - how to inspect it with
echo $PATH - how to ask which file wins with
which - how to make a temporary PATH change with
export - why
PATHcounts as an environment variable in the first place - why that temporary fix disappears in a new shell
- the footgun for this lesson: a fix you make with
exportonly changes the current shell
what this assumes
terminal 101 through terminal 104.
if the Homebrew lesson made sense and which brew no longer feels mysterious, you’re ready for the reason underneath it.
3 commands + 1 environment variable
this lesson stays Mac-first so it connects cleanly to 104, but the mental model is broader than macOS.
| what you want to do | command | what it means |
|---|---|---|
| show the shell’s search list | echo $PATH | print the PATH directories in order |
| ask which file a command resolves to | which rg | show the first matching executable the shell will run |
| temporarily put a folder at the front | export PATH="$HOME/bin:$PATH" | change PATH for the current shell session only |
the search rule is the real lesson:
the shell walks through PATH from left to right, and the first match wins
that one sentence explains both of these beginner problems:
- “why is my custom script not found even though the file exists?”
- “why is the wrong copy of
python3running?“
try it yourself
the interactive demo below is designed to make the invisible part visible.
the shipit preset is a stand-in for any small helper script you might save in ~/bin.
work through this order:
- leave the default
python3preset selected - click
run which - notice that the first
python3match wins, even though another copy exists later - click the
shipitpreset - click
run whichagain - see the second beginner problem: the command exists, but the current PATH is not searching
~/bin - click
echo $PATH - click
export PATH="$HOME/bin:$PATH" - click
run which - click
open new shell - click
run whichone more time
the teaching moment is steps 8 through 11:
exportcan fix the current shell immediately- but it does not automatically change future shells
that’s why “it worked a second ago” and “it disappeared in the next tab” can both be true.
ใน terminal 104 เราเห็นอาการที่ชวนรำคาญของปัญหานี้ไปแล้วครับ:
- เครื่องมือมีอยู่จริง
- การติดตั้งก็สำเร็จ
- แต่ shell ยังบอกว่า “command not found”
105 คือจุดที่เรื่องนี้จะเลิกดูสุ่มครับ
ชื่อของภาพจำที่ขาดไปคือ PATH
PATH ก็คือ “รายชื่อโฟลเดอร์” ที่ shell จะไล่ค้นหาเวลาคุณพิมพ์ชื่อคำสั่งอย่าง rg, git, หรือ python3
ในบทนี้คำว่า “ตัวแปรแวดล้อม” จะหมายถึงตัวอย่างสำคัญตัวเดียวเป็นหลัก คือ PATH ครับ ตั้งใจให้แคบแบบนี้ เพราะคุณยังไม่ต้องได้สารานุกรมเรื่องนี้ คุณต้องการแค่ตัวแปรเดียวที่ช่วยอธิบายปัญหามือใหม่ได้ทันที
พอเข้าใจลำดับการค้นหานี้ ความงงเรื่อง terminal จำนวนมากจะยุบลงเหลือแค่ 3 คำถาม:
- ไฟล์นั้นมีอยู่จริงไหม
- โฟลเดอร์ของมันอยู่ใน
PATHหรือเปล่า - ถ้ามีมากกว่าหนึ่งชุด ตัวไหนชนะ
จบโพสต์นี้แล้วจะทำอะไรได้บ้าง
- เข้าใจว่า
PATHคืออะไรแบบไม่ต้องใช้ศัพท์ยาก - เช็กมันได้ด้วย
echo $PATH - ถามได้ว่าคำสั่งจริงๆ ชี้ไปไฟล์ไหนด้วย
which - เปลี่ยน PATH ชั่วคราวด้วย
export - เข้าใจว่า
PATHเองก็คือ environment variable ตัวหนึ่ง - เข้าใจว่าทำไมวิธีแก้แบบชั่วคราวถึงหายไปเมื่อเปิด shell ใหม่
- จำจุดพลาดสำคัญของบทนี้ได้: สิ่งที่แก้ด้วย
exportมีผลแค่ shell ปัจจุบัน
โพสต์นี้เริ่มจากไหน
ผ่าน terminal 101 ถึง terminal 104 มาแล้วจะลื่นสุดครับ
ถ้าบท Homebrew เริ่มชัดขึ้นแล้ว และ which brew ไม่ดูเป็นเวทมนตร์อีกต่อไป ก็พร้อมสำหรับเหตุผลที่อยู่ข้างใต้แล้วครับ
3 คำสั่ง + 1 ตัวแปรแวดล้อม
บทนี้ยังยึดตัวอย่างแบบเริ่มจาก Mac เป็นหลัก เพื่อให้ต่อจาก 104 ได้ลื่น
แต่ภาพจำหลักจริงๆ ใช้ได้กว้างกว่าบน macOS อย่างเดียวครับ
| สิ่งที่อยากทำ | คำสั่ง | ความหมาย |
|---|---|---|
| ดูรายการโฟลเดอร์ที่ shell ใช้ค้นหา | echo $PATH | พิมพ์ PATH ออกมาตามลำดับ |
| ถามว่าคำสั่งนี้จะวิ่งไปไฟล์ไหน | which rg | แสดง executable ตัวแรกที่ shell จะเลือกใช้ |
| เอาโฟลเดอร์หนึ่งขึ้นมาไว้ด้านหน้าแบบชั่วคราว | export PATH="$HOME/bin:$PATH" | เปลี่ยน PATH ของ shell ปัจจุบันเท่านั้น |
กฎที่สำคัญจริงๆ มีประโยคเดียว:
shell จะไล่ PATH จากซ้ายไปขวา และ ตัวที่เจอก่อนชนะ
ประโยคนี้อธิบายปัญหามือใหม่ได้พร้อมกันสองแบบ:
- “ทำไม script ของฉันมีไฟล์อยู่แล้ว แต่ยังหาไม่เจอ?”
- “ทำไม
python3คนละตัวกับที่คิดถึงถูกเรียกขึ้นมา?”
ลองเล่นดู
เดโมด้านล่างออกแบบมาเพื่อทำให้สิ่งที่ปกติมองไม่เห็น มองเห็นได้ครับ
preset shipit ใช้แทน helper script เล็กๆ ที่คุณอาจเซฟไว้ใน ~/bin
ลองตามลำดับนี้:
- ปล่อย preset เริ่มต้นไว้ที่
python3 - กด
run which - สังเกตว่า
python3ตัวแรกชนะ ถึงแม้จะมีอีกตัวอยู่ลึกลงไป - เปลี่ยนเป็นตัวอย่าง
shipit - กด
run whichอีกรอบ - จะเห็นปัญหาอีกแบบ: คำสั่งมีอยู่จริง แต่ PATH ปัจจุบันยังไม่ค้นหา
~/bin - กด
echo $PATH - กด
export PATH="$HOME/bin:$PATH" - กด
run which - กด
open new shell - กด
run whichอีกครั้ง
หัวใจของบทนี้อยู่ที่ข้อ 8 ถึง 11:
exportแก้ shell ปัจจุบันได้ทันที- แต่มัน ไม่ได้ เปลี่ยน shell ใหม่ให้เองอัตโนมัติ
เพราะงั้นประโยคว่า “เมื่อกี้ยังใช้ได้อยู่เลย” กับ “เปิดแท็บใหม่แล้วหาย” จึงจริงพร้อมกันได้ครับ
Path visualizerตัวช่วยมอง PATH
Try a command name, watch the shell walk through PATH from top to bottom, and see why a temporary export works only in the current shell window.ลองพิมพ์ชื่อคำสั่ง แล้วดูว่า shell ไล่ค้นหา PATH จากบนลงล่างอย่างไร และทำไม export แบบชั่วคราวถึงมีผลแค่ใน shell ปัจจุบัน
what PATH really is
you do not need a textbook definition here.
PATH is just a colon-separated list of directories:
echo $PATHwhen you type:
rg notesthe shell does not magically know where rg lives.
it checks each PATH directory in order until it finds a matching executable. if /opt/homebrew/bin comes before /usr/bin, then commands in /opt/homebrew/bin get first chance.
that is why order matters.
why PATH is an environment variable
an environment variable is just a named piece of shell state.
PATH is one of those named values. when you run:
echo $PATHyou are asking the shell to print the current value stored under the name PATH.
that is enough environment-variable theory for now. the point is not to memorize jargon. the point is to understand that PATH is data the shell carries around, uses while resolving commands, and can change for the current session.
why which is worth learning early
which answers a very practical question:
“if i type this command name right now, what file will the shell actually run?”
examples:
which brew
which rg
which python3if which prints a path, the shell can resolve the command.
if it cannot, you know the problem is not “typing the command wrong.” the problem is that the shell cannot find a matching file in its current search path.
that distinction saves a lot of wasted reinstalling and random copying.
what export changes, and what it does not
this line is useful:
export PATH="$HOME/bin:$PATH"it means:
- take
~/bin - put it at the front
- keep the old PATH after it
that change affects the current shell process.
it does not rewrite history, and it does not automatically configure future shells. if you close the window or open a fresh one, the temporary change is gone unless your startup files add it again.
that is exactly why 105 comes before 106.
105 teaches the mental model.
106 teaches where to put the change so it sticks.
one real-world task
imagine you made a tiny helper script called shipit and saved it in ~/bin.
the workflow looks like this:
- run
which shipit - if it does not resolve, check
echo $PATH - temporarily test with
export PATH="$HOME/bin:$PATH" - run
which shipitagain - if
which shipitnow prints a path, the PATH part is fixed - if that fixed it, make the change persistent in your shell config instead of retyping
exportforever
that is a real beginner workflow because it separates three jobs cleanly:
- verify
- test the fix
- then make the fix permanent in the right place
whether the script itself runs correctly after that is a separate question. PATH only decides whether the shell can find it.
common mistakes
you treat PATH like one mysterious string instead of an ordered list. order is the whole point. leftmost directories get checked first.
you assume a file existing somewhere means the shell can run it. the shell only searches the directories currently in PATH.
you forget that export is temporary. this is the footgun for 105. if the fix vanishes in a new tab, nothing supernatural happened.
you keep guessing instead of checking with which. use the cheap evidence first.
you jump straight to editing config files without testing the idea in the current shell. a temporary export is a good experiment. if it works, then move the change into shell config.
what this unlocks
now “command not found” should feel narrower and easier to debug.
you can check PATH, see which executable wins, and prove whether a change is temporary or persistent.
next up: terminal 106 — shell config on macOS. that’s where PATH changes, aliases, and source ~/.zshrc stop being copy-paste rituals and start making sense.
PATH จริงๆ คืออะไร
ตอนนี้ยังไม่ต้องใช้คำนิยามแบบตำราก็ได้ครับ
PATH คือรายการโฟลเดอร์ที่คั่นด้วย ::
echo $PATHเวลาเราพิมพ์:
rg notesshell ไม่ได้ “รู้อยู่แล้ว” ว่า rg อยู่ตรงไหน
มันจะไล่เช็กทีละโฟลเดอร์ตามลำดับใน PATH จนกว่าจะเจอ executable ที่ชื่อตรงกัน ถ้า /opt/homebrew/bin มาก่อน /usr/bin คำสั่งใน /opt/homebrew/bin ก็ได้สิทธิ์ก่อน
เพราะงั้น “ลำดับ” จึงสำคัญครับ
ทำไม PATH ถึงนับเป็น environment variable
environment variable ก็คือค่าชิ้นหนึ่งที่ shell เก็บไว้โดยมีชื่อกำกับ
PATH ก็เป็นค่าชื่อหนึ่งในนั้น พอคุณรัน:
echo $PATHคุณกำลังขอให้ shell พิมพ์ค่าปัจจุบันที่เก็บไว้ภายใต้ชื่อ PATH ออกมา
ทฤษฎีเรื่อง environment variable สำหรับตอนนี้เอาแค่นี้พอครับ จุดสำคัญไม่ใช่การท่องศัพท์ แต่คือการเห็นว่า PATH เป็นข้อมูลที่ shell พกอยู่ ใช้ตอนหาคำสั่ง และเปลี่ยนได้สำหรับ session ปัจจุบัน
ทำไมควรรู้จัก which ตั้งแต่เนิ่นๆ
which ตอบคำถามที่ใช้การได้จริงมาก:
“ถ้าฉันพิมพ์ชื่อนี้ตอนนี้ shell จะไปรันไฟล์ไหน?”
ตัวอย่าง:
which brew
which rg
which python3ถ้า which พิมพ์ path ออกมา แปลว่า shell resolve คำสั่งนี้ได้
ถ้าไม่เจอ ก็แปลว่าปัญหาไม่ใช่ “พิมพ์ชื่อผิด” แต่เป็น “shell หาไฟล์ที่ตรงกันใน search path ปัจจุบันไม่เจอ”
แค่แยกสองกรณีนี้ให้ชัด ก็ช่วยลดการติดตั้งซ้ำแบบเดาสุ่มได้มากแล้วครับ
export เปลี่ยนอะไร และไม่ได้เปลี่ยนอะไร
บรรทัดนี้มีประโยชน์มาก:
export PATH="$HOME/bin:$PATH"มันแปลว่า:
- เอา
~/bin - วางไว้ด้านหน้า
- แล้วต่อ PATH เดิมตามหลังไป
การเปลี่ยนนี้มีผลกับ process ของ shell ปัจจุบัน
มันไม่ได้ย้อนเวลาไปแก้ shell ที่เปิดใหม่ในอนาคตให้เอง และไม่ได้ทำให้ค่าถาวรโดยอัตโนมัติ ถ้าปิดหน้าต่างนี้หรือเปิดหน้าต่างใหม่ การเปลี่ยนชั่วคราวจะหายไป เว้นแต่ startup file ของคุณจะเป็นคนเติมมันกลับมา
นี่แหละครับว่าทำไม 105 ถึงมาก่อน 106
105 สอนภาพจำ
ส่วน 106 จะสอนว่าควรวางค่าพวกนี้ไว้ตรงไหนถ้าอยากให้มันอยู่ถาวร
โจทย์จากโลกจริง
สมมติว่าคุณมี helper script เล็กๆ ชื่อ shipit แล้วเก็บไว้ใน ~/bin
flow จะเป็นแบบนี้:
- รัน
which shipit - ถ้ายังไม่เจอ ให้เช็ก
echo $PATH - ทดลองแก้แบบชั่วคราวด้วย
export PATH="$HOME/bin:$PATH" - รัน
which shipitอีกรอบ - ถ้า
which shipitพิมพ์ path ออกมา แปลว่าส่วนของ PATH ถูกแก้แล้ว - ถ้าใช่วิธีนี้จริง ค่อยย้ายวิธีแก้นั้นไปเก็บใน shell config แทนการพิมพ์
exportซ้ำไปเรื่อยๆ
นี่เป็น workflow ของมือใหม่ที่ใช้ได้จริง เพราะมันแยกงานออกจากกันชัด:
- ตรวจให้เห็นก่อน
- ทดลองแก้
- แล้วค่อยทำให้ถาวรในที่ที่ถูกต้อง
ส่วนที่ว่า script จะรันได้สมบูรณ์ไหมหลังจากนั้น เป็นอีกคำถามหนึ่งครับ PATH มีหน้าที่แค่ทำให้ shell “หาเจอ” ก่อน
ข้อผิดพลาดที่พบบ่อย
มอง PATH เป็นสตริงลึกลับก้อนเดียว แทนที่จะมองเป็นรายการที่มีลำดับ ลำดับคือหัวใจเลยครับ โฟลเดอร์ทางซ้ายถูกค้นก่อน
คิดว่าแค่มีไฟล์อยู่ที่ไหนสักแห่งก็แปลว่า shell รันได้ shell จะค้นหาเฉพาะโฟลเดอร์ที่อยู่ใน PATH ตอนนี้เท่านั้น
ลืมว่า export เป็นของชั่วคราว นี่คือ footgun ของ 105 เลยครับ ถ้าวิธีแก้หายไปในแท็บใหม่ มันไม่ได้เกิดเรื่องลี้ลับอะไร
เดาไปเรื่อยแทนที่จะเช็กด้วย which ใช้หลักฐานที่ถูกและเร็วที่สุดก่อน
กระโดดไปแก้ config file ทันทีโดยยังไม่ได้ทดลองใน shell ปัจจุบัน export ชั่วคราวคือการทดลองที่ดี ถ้ามันเวิร์ก ค่อยย้ายไปไว้ใน shell config
เปิดประตูไปต่อที่ไหน
จากนี้คำว่า “command not found” ควรจะรู้สึกแคบลง และแกะได้ง่ายขึ้นแล้วครับ
คุณดู PATH ได้ ดูได้ว่า executable ตัวไหนชนะ และพิสูจน์ได้ว่าการเปลี่ยนหนึ่งๆ เป็นของชั่วคราวหรือถาวร
ตอนต่อไปคือ terminal 106 — shell config on macOS ตรงนั้นเรื่อง PATH, alias, และ source ~/.zshrc จะเลิกเป็นการคัดลอกคำสั่งตามคนอื่น แล้วกลายเป็นสิ่งที่อธิบายได้ว่ากำลังทำอะไรอยู่ครับ