Ruby ma trzy sposoby podania nazwy wywoływanego skryptu:
#!/usr/bin/env ruby
puts "$0 : #{$0}"
puts "__FILE__ : #{__FILE__}"
puts "$PROGRAM_NAME : #{$PROGRAM_NAME}"
Zapisanie tego kodu jako „test.rb” i wywołanie go na kilka sposobów pokazuje, że skrypt otrzymuje taką nazwę, jaka została mu przekazana przez system operacyjny. Skrypt wie tylko, co mówi mu system operacyjny:
$ ./test.rb
$0 : ./test.rb
__FILE__ : ./test.rb
$PROGRAM_NAME : ./test.rb
$ ~/Desktop/test.rb
$0 : /Users/ttm/Desktop/test.rb
__FILE__ : /Users/ttm/Desktop/test.rb
$PROGRAM_NAME : /Users/ttm/Desktop/test.rb
$ /Users/ttm/Desktop/test.rb
$0 : /Users/ttm/Desktop/test.rb
__FILE__ : /Users/ttm/Desktop/test.rb
$PROGRAM_NAME : /Users/ttm/Desktop/test.rb
Wywołanie go za pomocą ~
skrótu do $ HOME w drugim przykładzie pokazuje, że system operacyjny zastępuje go rozszerzoną ścieżką, dopasowując to, co jest w trzecim przykładzie. We wszystkich przypadkach to właśnie przekazał system operacyjny.
Tworzenie linków do pliku przy użyciu zarówno twardych, jak i miękkich linków jest spójne. Utworzyłem link twardy do test1.rb i link miękki do test2.rb:
$ ./test1.rb
$0 : ./test1.rb
__FILE__ : ./test1.rb
$PROGRAM_NAME : ./test1.rb
$ ./test2.rb
$0 : ./test2.rb
__FILE__ : ./test2.rb
$PROGRAM_NAME : ./test2.rb
Uruchomienie ruby test.rb
z dowolną odmianą nazwy skryptu zwraca spójne wyniki.
Jeśli chcesz tylko wywoływanej nazwy pliku, możesz użyć basename
metody File z jedną ze zmiennych lub podzielić separator i wziąć ostatni element.
$0
i __FILE__
mają drobne różnice, ale dla pojedynczych skryptów są równoważne.
puts File.basename($0)
Istnieją pewne korzyści użyciu File.basename
, File.extname
oraz File.dirname
zestaw metod. basename
przyjmuje opcjonalny parametr, który jest rozszerzeniem strip, więc jeśli potrzebujesz tylko nazwy basename bez rozszerzenia
File.basename($0, File.extname($0))
robi to bez ponownego wynalezienia koła lub konieczności radzenia sobie ze zmienną długością lub brakującymi przedłużeniami lub możliwością nieprawidłowego obcięcia łańcuchów przedłużających, .rb.txt
na przykład:
ruby-1.9.2-p136 :004 > filename = '/path/to/file/name.ext'
=> "/path/to/file/name.ext"
ruby-1.9.2-p136 :005 > File.basename(filename, File.extname(filename))
=> "name"
ruby-1.9.2-p136 :006 > filename = '/path/to/file/name.ext' << '.txt'
=> "/path/to/file/name.ext.txt"
ruby-1.9.2-p136 :007 > File.basename(filename, File.extname(filename))
=> "name.ext"
ta odpowiedź może przyjść trochę za późno, ale miałem ten sam problem, a zaakceptowana odpowiedź nie wydawała mi się całkiem satysfakcjonująca, więc poszukałem nieco dalej.
Co mi nie przeszkadzało to fakt, że
$0
albo$PROGRAM_NAME
tak naprawdę nie posiadają prawidłowe informacje o tym, co użytkownik miał wpisane . Jeśli mój skrypt Ruby znajdował się w folderze PATH, a użytkownik wprowadził nazwę pliku wykonywalnego (bez żadnych definicji ścieżek, takich jak./script
lub/bin/script
), zawsze rozwijałby się on do ścieżki całkowitej.Myślałem, że to niedobór Rubiego, więc spróbowałem tego samego z Pythonem i ku mojemu rozczarowaniu nie było inaczej.
Znajomy zasugerował mi, żebym poszukał
real thing
in/proc/self/cmdline
, a wynik był następujący:[ruby, /home/danyel/bin/myscript, arg1, arg2...]
(oddzielone znakiem null-char). Ten złoczyńca jest tym,execve(1)
który rozszerza ścieżkę do całkowitej ścieżki, kiedy przekazuje ją tłumaczowi.Przykładowy program w C:
#include <stdlib.h> #include <unistd.h> extern char** environ; int main() { char ** arr = malloc(10 * sizeof(char*)); arr[0] = "myscript"; arr[1] = "-h"; arr[2] = NULL; execve("/home/danyel/bin/myscript", arr, environ); }
Wynik: Użycie: / home / danyel / bin / myscript PLIK ...
Aby udowodnić, że to rzeczywiście jest
execve
rzecz, a nie z basha, możemy stworzyć fałszywego interpretera, który nic nie robi, tylko wypisuje przekazane mu argumenty:// interpreter.c int main(int argc, const char ** argv) { while(*argv) printf("%s\n", *(argv++)); }
Kompilujemy go i umieszczamy w folderze ze ścieżką (lub umieszczamy pełną ścieżkę po shebang) i tworzymy fałszywy skrypt w
~/bin/myscript/
#!/usr/bin/env interpreter Hi there!
Teraz w naszym main.c:
#include <stdlib.h> extern char** environ; int main() { char ** arr = malloc(10 * sizeof(char*)); arr[0] = "This will be totally ignored by execve."; arr[1] = "-v"; arr[2] = "/var/log/apache2.log"; arr[3] = NULL; execve("/home/danyel/bin/myscript", arr, environ); }
Kompilowanie i uruchamianie
./main
: interpreter / home / danyel / bin / myscript -v /var/log/apache2.logPrzyczyną tego jest najprawdopodobniej to, że jeśli skrypt znajduje się w Twojej PATH, a pełna ścieżka nie została podana, interpreter rozpozna to jako
No such file
błąd, co zrobi, jeśli to zrobisz:ruby myrubyscript --options arg1
i nie ma Cię w folderze z tym skryptem .źródło
Użyj
$0
lub,$PROGRAM_NAME
aby uzyskać nazwę aktualnie wykonywanego pliku.źródło
/usr/local/bin/myScript
i/usr/local/bin
jest w moim$PATH
, a po prostumyScript
piszę, dostaję/usr/local/bin/myScript
od$0
$0.split("/").last
?./myScript
, potrzebuję zmiennej, która mi daje./myScript
. Jeśli napisali/usr/bin/local/myScript
, chcę dokładnie tego. itd.To nie jest do końca odpowiedź na twoje pytanie, ale brzmi to tak, jakbyś na nowo odkrywał koło. Spójrz na bibliotekę optparse . Pozwala zdefiniować przełączniki wiersza poleceń, argumenty itp. I wykona za Ciebie całą ciężką pracę.
źródło