Mengapa Anda perlu ./ (dot-slash) sebelum dieksekusi atau nama skrip untuk menjalankannya di bash?

288

Saat menjalankan skrip di bash, saya harus menulis ./di awal:

$ ./manage.py syncdb

Jika tidak, saya mendapat pesan kesalahan:

$ manage.py syncdb
-bash: manage.py: command not found

Apa alasannya? Saya pikir .ini adalah alias untuk folder saat ini, dan oleh karena itu kedua panggilan ini harus sama.

Saya juga tidak mengerti mengapa saya tidak perlu ./ketika menjalankan aplikasi, seperti:

user:/home/user$ cd /usr/bin
user:/usr/bin$ git

(yang berjalan tanpa ./)

Dan Abramov
sumber
4
Ini adalah dokumen terbaik tentang masalah yang saya temui sejauh ini: linfo.org/dot_slash.html
odigity

Jawaban:

307

Karena pada Unix, biasanya, direktori saat ini tidak dalam $PATH.

Saat Anda mengetik perintah, shell mencari daftar direktori, seperti ditentukan oleh PATHvariabel. Direktori saat ini tidak ada dalam daftar itu.

Alasan tidak memiliki direktori saat ini pada daftar itu adalah keamanan.

Katakanlah Anda root dan masuk ke direktori pengguna lain dan ketik slbukan ls. Jika direktori saat ini di PATH, shell akan mencoba untuk menjalankan slprogram di direktori itu (karena tidak ada slprogram lain ). Itu slProgram mungkin berbahaya.

Ini bekerja dengan ./karena POSIX menentukan bahwa nama perintah yang berisi /akan digunakan sebagai nama file secara langsung, menekan pencarian di $PATH. Anda bisa menggunakan path lengkap untuk efek yang sama persis, tetapi ./lebih pendek dan lebih mudah untuk ditulis.

EDIT

Itu slbagian itu hanya contoh. Direktori di PATHdicari secara berurutan dan ketika pertandingan dibuat bahwa program dieksekusi. Jadi, tergantung pada PATHtampilannya, mengetik perintah normal mungkin atau mungkin tidak cukup untuk menjalankan program di direktori saat ini.

cnicutar
sumber
47
Anda tidak perlu salah ketik apa pun. Pengguna mungkin baru saja mengunduh paket jahat yang berisi lsfile yang dapat dieksekusi di dalamnya.
Juliano
13
Hanya sebuah catatan untuk semua orang yang mengatakan ini hanya di Unix dan bukan Windows, ini sama di Powershell - Anda harus melakukan .\my.batdll untuk mengeksekusi
manojlds
1
@gaearon ergh, saya katakan "bukan alias", padahal seharusnya "ketat alias".
Charles Duffy
4
Itu penjelasan yang sangat membantu. 20+ tahun yang lalu ketika saya bekerja dengan DOS sedikit, saya pikir CMD akan memeriksa direktori saat ini, MAKA JALAN, jadi perilaku Linux bukanlah yang saya harapkan, tapi itu BANYAK akal.
TecBrat
2
@cnicutar: Menariknya hari ini saya menemukan bahwa ada slperintah yang disebut lokomotif uap meskipun tidak tersedia secara default ;-)
blackSmith
51

Ketika bash menginterpretasikan baris perintah, ia mencari perintah di lokasi yang dijelaskan dalam variabel lingkungan $PATH. Untuk melihatnya ketik:

echo $PATH

Anda akan memiliki beberapa jalur yang dipisahkan oleh titik dua. Seperti yang Anda lihat, path saat .ini biasanya tidak dalam $PATH. Jadi Bash tidak dapat menemukan perintah Anda jika ada di direktori saat ini. Anda dapat mengubahnya dengan memiliki:

PATH=$PATH:.

Baris ini menambahkan direktori saat ini $PATHsehingga Anda dapat melakukan:

manage.py syncdb

Hal ini tidak dianjurkan karena memiliki masalah keamanan, ditambah Anda dapat memiliki perilaku aneh, seperti .bervariasi pada direktori Anda berada di :)

Menghindari:

PATH=.:$PATH

Karena Anda dapat "menutupi" beberapa perintah standar dan membuka pintu untuk pelanggaran keamanan :)

Hanya dua sen saya.

neuro
sumber
42

Script Anda, ketika di direktori home Anda tidak akan ditemukan ketika shell melihat $PATHvariabel lingkungan untuk menemukan script Anda.

The ./mengatakan 'lihat di direktori saat ini untuk naskah saya daripada melihat semua direktori yang ditentukan dalam $PATH'.

mdm
sumber
5

Ketika Anda memasukkan '.' Anda pada dasarnya memberikan "path lengkap" ke skrip bash yang dapat dieksekusi, jadi shell Anda tidak perlu memeriksa variabel PATH Anda. Tanpa '.' shell Anda akan melihat dalam variabel PATH Anda (yang dapat Anda lihat dengan menjalankan echo $PATHuntuk melihat apakah perintah yang Anda ketikkan tinggal di salah satu folder di PATH Anda. Jika tidak (seperti halnya dengan manage.py) ia mengatakannya tidak dapat menemukan file. Ini dianggap praktik buruk untuk memasukkan direktori saat ini di PATH Anda, yang dijelaskan dengan cukup baik di sini: http://www.faqs.org/faqs/unix-faq/faq/part2/section- 13.html

Mark Drago
sumber
2

Pada * nix, tidak seperti Windows, direktori saat ini biasanya tidak dalam $PATHvariabel Anda . Jadi direktori saat ini tidak dicari ketika menjalankan perintah. Anda tidak perlu ./menjalankan aplikasi karena aplikasi ini ada dalam $ PATH Anda; kemungkinan besar mereka berada di /binatau /usr/bin.

Anomie
sumber
1

Pertanyaan ini sudah memiliki beberapa jawaban yang luar biasa, tetapi saya ingin menambahkan itu, jika executable Anda ada di PATH, dan Anda mendapatkan output yang sangat berbeda ketika Anda menjalankan

./executable

ke yang Anda dapatkan jika Anda berlari

executable

(misalkan Anda mengalami pesan kesalahan dengan yang satu dan bukan yang lain), maka masalahnya bisa jadi Anda memiliki dua versi yang dapat dieksekusi pada mesin Anda: satu di jalan, dan yang lainnya tidak.

Periksa ini dengan menjalankan

yang dapat dieksekusi

dan

whereis executable

Itu memperbaiki masalah saya ... Saya punya tiga versi yang dapat dieksekusi, hanya satu yang dikompilasi dengan benar untuk lingkungan.

KR_Henninger
sumber
0

Dasar pemikiran untuk aturan /POSIX PATH

Aturan disebutkan di: Mengapa Anda perlu ./ (dot-slash) sebelum dieksekusi atau nama skrip untuk menjalankannya dalam bash? tapi saya ingin menjelaskan mengapa saya pikir itu adalah desain yang bagus dengan lebih detail.

Pertama, versi lengkap aturan secara eksplisit adalah:

  • jika path berisi /(mis ./someprog. /bin/someprog,./bin/someprog ): CWD digunakan dan PATH tidak
  • jika path tidak mengandung /(misalnya someprog): PATH digunakan dan CWD tidak

Sekarang, misalkan menjalankan itu:

someprog

akan mencari:

  • relatif terhadap CWD pertama
  • relatif terhadap PATH setelah

Kemudian, jika Anda ingin lari /bin/someprogdari distro Anda, dan Anda melakukannya:

someprog

kadang-kadang akan berfungsi, tetapi yang lain akan gagal, karena Anda mungkin berada di direktori yang berisi someprogprogram lain yang tidak terkait

Oleh karena itu, Anda akan segera mengetahui bahwa ini tidak dapat diandalkan, dan Anda akan selalu selalu menggunakan jalur absolut ketika Anda ingin menggunakan PATH, karena itu mengalahkan tujuan PATH.

Ini juga mengapa memiliki jalur relatif di PATH Anda adalah ide yang sangat buruk. Saya melihat Anda,node_modules/bin .

Sebaliknya, misalkan menjalankan:

./someprog

Akan mencari:

  • relatif terhadap PATH terlebih dahulu
  • relatif terhadap CWD setelah

Kemudian, jika Anda baru saja mengunduh skrip someprogdari repositori git dan ingin menjalankannya dari CWD, Anda tidak akan pernah yakin bahwa ini adalah program aktual yang akan dijalankan, karena mungkin distro Anda memiliki:

/bin/someprog

yang ada di Anda PATH dari beberapa paket yang Anda instal setelah minum terlalu banyak setelah Natal tahun lalu.

Karena itu, sekali lagi, Anda akan dipaksa untuk selalu menjalankan skrip lokal relatif terhadap CWD dengan path lengkap untuk mengetahui apa yang Anda jalankan:

"$(pwd)/someprog"

yang akan sangat mengganggu juga.

Aturan lain yang mungkin membuat Anda tergoda untuk melakukannya adalah:

jalur relatif hanya menggunakan PATH, jalur absolut hanya CWD

tetapi sekali lagi ini memaksa pengguna untuk selalu menggunakan jalur absolut untuk skrip non-PATH "$(pwd)/someprog".

The /aturan penelusuran jalur menawarkan sederhana untuk mengingat solusi untuk tentang masalah:

  • slash: jangan gunakan PATH
  • tidak ada garis miring: hanya gunakan PATH

yang membuatnya sangat mudah untuk selalu tahu apa yang Anda jalankan, dengan mengandalkan fakta bahwa file dalam direktori saat ini dapat dinyatakan sebagai ./somefileatau somefile, dan karenanya memberikan makna khusus kepada salah satu dari mereka.

Kadang-kadang, sedikit menjengkelkan bahwa Anda tidak dapat mencari some/progrelatif terhadap PATH, tetapi saya tidak melihat solusi yang lebih waras untuk ini.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
sumber
-1

Ketika skrip tidak ada di Path, wajib untuk melakukannya. Untuk info lebih lanjut baca http://www.tldp.org/LDP/Bash-Beginners-Guide/html/sect_02_01.html

Gayan Hewa
sumber
5
... FYI, dalam #bash di irc.freenode.org, kami terus memperbaiki kesalahpahaman yang telah dipelajari orang-orang dari TLDP (khususnya Panduan Bash Lanjutan). Dengan demikian, mengarahkan orang ada ... mungkin tidak ideal. (Dokumentasi pengantar pilihan kami adalah mywiki.wooledge.org/BashGuide )
Charles Duffy
-2

Semua memiliki jawaban yang bagus pada pertanyaan, dan ya ini hanya berlaku ketika menjalankannya di direktori saat ini, kecuali jika Anda menyertakan jalur absolut. Lihat contoh saya di bawah ini.

Juga, (dot-slash) masuk akal bagi saya ketika saya sudah perintah pada folder anak tmp2 (/ tmp / tmp2) dan menggunakan (double dot-slash).

SAMPEL:

[fifiip-172-31-17-12 tmp]$ ./StackO.sh

Hello Stack Overflow

[fifi@ip-172-31-17-12 tmp]$ /tmp/StackO.sh

Hello Stack Overflow

[fifi@ip-172-31-17-12 tmp]$ mkdir tmp2

[fifi@ip-172-31-17-12 tmp]$ cd tmp2/

[fifi@ip-172-31-17-12 tmp2]$ ../StackO.sh

Hello Stack Overflow
FIFI
sumber