Wykonaj jako .test zamiast ./test

26

Przypuśćmy, że jestem w tym samym folderze co plik wykonywalny, musiałbym wpisać to, aby go wykonać:

./file

Wolałbym nie pisać /, bo /trudno mi pisać.

Czy istnieje łatwiejszy sposób wykonania pliku? Idealnie po prostu prosta składnia, taka jak:

.file

lub coś innego, ale łatwiejsze niż wstawianie /tam postaci.

Być może istnieje jakiś sposób na umieszczenie czegoś w /binkatalogu lub utworzenie aliasu dla interpretera, aby móc użyć:

p file
IMSoP
źródło
9
Może zamień / z innym kluczem za pomocą xmodmap? Przynajmniej łatwiej jest pisać
Guy
26
Na marginesie, /jest szeroko stosowany w Uniksie, głównie jako separator katalogów. Prawdopodobnie lepiej jest znaleźć łatwiejszy sposób na wpisanie go.
Chrylis
7
@RossPresser To pytanie ma bardzo mało sensu. i ./ na początku pliku mają dwa zupełnie różne znaczenia z przyczyn technicznych, które każdy początkujący powinien wiedzieć. /dla większości ludzi nie jest trudne do pisania, a jeśli OP dozna obrażeń, które temu zapobiegają, powinni rozważyć alternatywne układy klawiatury, ponieważ nie ma możliwości, aby /całkowicie uniknąć, gdy są w terminalu.
JFA
1
@JFA Większość układów klawiatury używanych w Europie kontynentalnej, a także w Ameryce Południowej, korzysta /z shift-7, którego pisanie jest stosunkowo trudne, nawet bez urazu.
nitro2k01
6
Edytuj historię: „ dlaczego nie można po prostu poinstruować interfejsu sieciowego, aby wykonywał wszystkie zapytania internetowe za pośrednictwem zdalnego hosta za pośrednictwem ssh na porcie 22. ” ಠ_ಠ
Derek 朕 會 功夫

Odpowiedzi:

35

Może to być „ryzykowne”, ale możesz po prostu mieć. w twojej ŚCIEŻCE.

Jak powiedziano w innych, może to być niebezpieczne, więc zawsze upewnij się. jest na końcu ŚCIEŻKI, a nie na początku.

HaloJones
źródło
1
Naprawdę nie rozumiem, jak to jest „ryzykowne”: moja droga była taka od dawna przed Linuksem i nigdy nie spowodowała najmniejszego problemu.
jamesqf
21
@jamesqf Jest to ryzykowne, ponieważ jeśli przejdziesz cddo katalogu, w którym można zapisywać na całym świecie, i spróbujesz użyć polecenia, które nie jest na twojej ścieżce, możesz wykonać (prawdopodobnie złośliwy) plik wykonywalny o tej samej nazwie, który ktoś napisał na tę ścieżkę. Jest to o wiele gorsze, jeśli umieścisz .na początku swojej ścieżki. W takim przypadku złośliwy plik wykonywalny o nazwie lszostanie wykonany, jeśli spróbujesz zadzwonić lsdo tego katalogu.
bajtował
2
Unikaj tego, z powodów określonych powyżej. pKomenda będzie lepiej.
Guido
11
@jamesqf Kiedy jest to „twój” system i tylko ty go używasz, nie jest tak źle. Problem pojawia się (i przez lata potknął wielu administratorów systemu Unix) w systemie z wieloma użytkownikami. Na .początku PATHszkodliwy użytkownik musi jedynie umieścić fałszywe lspolecenie w swoim katalogu i przekonać administratora, aby „spojrzał na coś dziwnego” i ma dostęp do konta root.
TripeHound,
1
Dobre rozwiązanie, choć nie zadziała, jeśli plik zostanie nazwany test, tak jak w tytule pytania (ponieważ testjest to wbudowana powłoka i prawdopodobnie istnieje już gdzieś w twoim pliku $PATH).
yellowantphil
71

.będzie automatycznie uzupełniać./ (pisać .i naciskać Tab) przynajmniej w nowoczesnych powłokach Bash, więc nie powinieneś używać złożonego lub niepewnego (jak PATHmodyfikacja) rozwiązania.

Jeśli nie zostanie ono automatycznie uzupełnione, może być konieczne zainstalowanie pakietu „bash-complete”.

10b0
źródło
Jesteś pewny? .ma wiele kandydatów do uzupełnienia: .(aktualny katalog), (katalog ..macierzysty), .polecenie (dla którego bash zapewnia niestandardowy alias source) oraz wszelkie obecne pliki dot. Może bash-completionpakiet ignoruje to; Uważam, że jest to okropnie denerwujące (np. Uniemożliwia uzupełnianie nazw katalogów tabulatorem w makewierszu poleceń i ogólnie jest okropne z plikami makefile zawierającymi niejawne reguły), więc zawsze go usuwam.
R ..
3
Próbowałem tego i tak, autouzupełnianie wykonuje się w ten sposób. W prawie każdym przypadku tego chciałby zwykły użytkownik: nie sądzę, żebym kiedykolwiek widział plik kropkowy, który powinien być wykonywalny, uruchamianie czegoś w podkatalogu jest znacznie częstsze niż uruchamianie czegoś w katalogu nadrzędnym, a IMO robi to cholernie dobra robota w znajdowaniu makecelów.
l0b0
W wersji bash 3.2 nie wykonuje się autouzupełniania. Czy to może być nowość w bash 4?
Calimo
2
@ Calimo Bardziej prawdopodobne nowe w ostatnich wersjach bash-complete. To nie jest zasadnicza zmiana.
l0b0
42

lub ... może nadając tłumaczowi alias w pliku bashrc, a następnie po prostu

   p  file

Możliwe jest napisanie takiej funkcji:

p() {
 ./"$@"
}

w twoim ~/.bashrc. Wtedy będziesz mógł uruchomić p app argumentszamiast ./app arguments. To rozwiązanie działa dla plików wykonywalnych dowolnego typu, w tym skryptów i plików binarnych.

"$@"rozwija się do odpowiednio cytowanej listy argumentów przekazywanych do funkcji (zachowując wszystkie znaki specjalne przed rozszerzeniem globalnym lub zmiennym) i, jak wskazał @Scott, bashjest wystarczająco sprytny, aby ./przejść do pierwszego z nich, zachowując resztę.

aitap
źródło
Chociaż jest to mniej ogólne w przypadku uruchamiania aplikacji pod innym poleceniem, na przykład strace -f p appwyświetlanie wywołań systemowych lub $(which time) p appsprawdzanie, jak długo to trwa. pponieważ skrypt wykonywalny działałby lepiej w tych dwóch konkretnych przykładach, które wymyśliłem. Żadne z tych rozwiązań nie może działać ldd p app, chociaż różni się ldd również wymaganiem pełnej ścieżki, być może z takich powodów.
sourcejedi
Tak, zastąpienie p app argsgo ./app argsw sposób niewidoczny dla każdego wymagałoby przepuszczenia danych wejściowych powłoki przez jakiś preprocesor i spowodowałoby wszelkiego rodzaju zabawę, gdy podstawienie nastąpiło w niezamierzonym miejscu :)
aitap
1
Czy w takim przypadku nie powinno być żadnych cytatów $@? W przeciwnym razie przekaże programowi tylko jeden duży argument.
Kroltan
7
@Kroltan No. $@to tablica. Po rozwinięciu "każdy parametr rozwija się do osobnego słowa. $*zachowuje się tak, jak myślisz.
8bittree
3
Uważam, że uczyniłeś to niepotrzebnie skomplikowanym i p() { ./"$@"; }to wszystko, czego potrzebujesz.
Scott
11

Możesz umieścić .na swoim $PATH, dodając np. PATH=$PATH:.Do swojego /etc/profile, w ten sposób możesz wykonać filepo prostu pisząc file, chyba że znajduje się w innym folderze na twojej ścieżce (np /usr/bin/.). Pamiętaj, że generalnie nie jest to dobry pomysł.

Dlaczego jest źle: Powiedzmy, że znajdujesz się w sytuacji, w której nie ufasz w pełni zawartości katalogu - pobrałeś go z podejrzanego miejsca i chcesz to sprawdzić przed uruchomieniem, lub jesteś administratorem systemu pomagającym niektórym użytkownika, przeglądając katalog domowy itp. Chcesz wyświetlić katalog, więc spróbuj wpisać ls, ale ups, popełnisz literówkę i zamiast tego napisałeś sl. Autor tego szkodliwego katalogu przewidział to i umieścił w nim skrypt powłoki o nazwie „sl”, który uruchamia „rm -rf --no-preserve-root /” (lub coś bardziej złośliwego, jak instalowanie rootkita).

(Dzięki @Muzer za wyjaśnienie)

phk
źródło
13
Chociaż szczerze się z tym zgadzam, to prawdopodobnie lepiej wyjaśnia dokładnie, dlaczego nie jest to dobry pomysł.
ymbirtt
16
Dlaczego jest źle: Powiedzmy, że znajdujesz się w sytuacji, w której nie ufasz w pełni zawartości katalogu - pobrałeś go z podejrzanego miejsca i chcesz to sprawdzić przed uruchomieniem, lub jesteś administratorem systemu pomagającym niektórym użytkownika, przeglądając katalog domowy itp. Chcesz wyświetlić katalog, więc spróbuj wpisać ls, ale ups, popełnisz literówkę i zamiast tego napisałeś sl. Autor tego szkodliwego katalogu przewidział to i umieścił w nim skrypt powłoki o nazwie „sl”, który uruchamia „rm -rf --no-preserve-root /” (lub coś bardziej złośliwego, jak instalowanie rootkita).
Muzer
2
Warto wyjaśnić, że jeśli bieżący katalog znajduje się na początku $ PATH, osoba atakująca może po prostu zastąpić ls lub inne popularne polecenia
Délisson Junio
@Muzer Huuuge kapelusze blaszane tutaj.
Kurczak Sombrero,
4
@GillBates Jest to coś, czego powinieneś być ostrożny jako administrator systemu, który ma do czynienia z rzeczywistymi i potencjalnie złośliwymi użytkownikami lub kimś, kto analizuje podejrzane archiwa w celu utrzymania. Jeśli żadne z nich nie ma zastosowania, zgadzam się z tobą. Nadal nie uważam, że warto się w to przyzwyczaić, ponieważ nigdy nie wiadomo, kiedy zmienią się okoliczności, dostajesz jedną z tych prac i nieskończenie przeklinasz się za to, że szkoliłeś się polegać na niepewnym zachowaniu; )
Muzer,
10

Możesz na przykład zadzwonić do tłumacza

bash test

W takim przypadku skrypt będzie działał, nawet jeśli nie będzie miał linii shebang (np. #!/bin/bash) Ani bitu wykonywalnego. Będziesz musiał znać poprawnego tłumacza, aby go uruchomić. Możesz najpierw przeczytać linię shebang pliku, aby upewnić się, że zadzwoniłeś do właściwego tłumacza, na przykład jeśli linia shebang mówi

#!/usr/bin/env python3

zadzwoniłbyś

python3 test
Zanna
źródło
7
interpreter po prostu interpretuje kod, nie będą uruchamiać plików binarnych
Mc Kernel
Ta odpowiedź jest nieco logiczna, ponieważ być może interpreter może otrzymać alias w pliku bashrc.
5
@McKernel dobry punkt, działa tylko wtedy, gdy istnieje interpreter, a nie dla skompilowanych plików wykonywalnych
Zanna 6'17
2
istnieje interpreter skompilowanych plików wykonywalnych:/lib/ld.so
Dmitrij Kudriavtsev
7

O ile mi wiadomo, nie ma sposobu na osiągnięcie tego, chyba że umieścisz plik w ścieżce env, więc możesz go uruchomić, wpisując: file

.filenie będzie działać, ponieważ jest to inna nazwa pliku. Jest to plik o nazwie .filei nie ./file.

Wyczuwam, że ukośnik może być dla ciebie trudny do napisania, ponieważ może nie w języku angielskim. W takim przypadku mi się to przydarza, więc często zamieniam układ klawiatury na angielski, naciskając Alt + Shift w systemie Windows (używam Linuksa z ssh)

Mc Kernel
źródło
7

Ludzie sugerują dodanie .do PATH, co jest niebezpieczne, ponieważ stwarza ryzyko, że przypadkowo uruchomisz złośliwy program umieszczony w katalogu do zapisu na całym świecie. Ale jeśli masz programy wykonywalne w kilku katalogach, które są właścicielami i zapisu tylko przez Ciebie, to jest to bezpieczne (dość bezpieczne?), Aby umieścić te reżyser (-a) się PATH, dodając taką linię

PATH=$PATH:~/dev/myprog1:~/dev/myprog2

do twojego ~/.bashrcpliku. Oczywiście oznacza to, że możesz uruchomić program z jednego z tych katalogów z dowolnego miejsca w systemie plików. Na przykład, możesz cd /etci pisz foo, a to się uruchomi ~/dev/myprog1/foo. Ma to niewielką wadę, że nie można mieć programów o tej samej nazwie w więcej niż jednym katalogu. W szczególności, jeśli masz programy wywoływane foo jednocześnie ~/dev/myprog1i ~/dev/myprog2nie będziesz mógł uruchomić drugiego, chyba że podasz ścieżkę. Podobnie, jeśli masz ~/dev/myprog1/cat- ale dlaczego chcesz?


Innym podejściem, jeśli masz tylko kilka programów, z którymi to robisz, jest zdefiniowanie dla nich aliasów:

alias gizmo='./gizmo'
alias gonzo='./gonzo'

Czy można nazwać aliasy .gizmoi .gonzo jeśli okaże się, że bardziej intuicyjne.

W rzeczywistości wiąże się to w pewnym stopniu z takim samym ryzykiem bezpieczeństwa, jak .w przypadku twojego PATH. Jeśli złośliwy użytkownik może odczytać .bashrci zobaczyć swoje aliasy, to może on umieścić złośliwego oprogramowania o nazwie gizmooraz gonzow przypadkowych katalogów, w nadziei, że będzie go uruchomić. Lepiej, aby używały bezwzględnych nazw ścieżek:

alias gizmo='~/dev/myprog1/gizmo'
alias gonzo='~/dev/myprog2/gonzo'

Nawiasem mówiąc, powinieneś unikać nazywania pliku wykonywalnego test, ponieważ jest to wbudowane polecenie powłoki, i możesz uruchomić program o tej nazwie tylko podając ścieżkę lub inną sztuczkę.

G-Man mówi „Przywróć Monikę”
źródło
Alternatywnie możesz zrobić przepis (jeśli używasz Makefiles) i zrobić make gizmolub make gonzo.
ihato
Przykro mi, ale nie jestem pewien, czy rozumiem, w jaki sposób odnosi się to do pytania lub mojej odpowiedzi. Czy sugerujesz, aby OP tworzył Makefilew każdym katalogu, tak aby akcje make gizmozakończyły się uruchomieniem gizmo ? (1) Wydaje się to niezręcznym sposobem robienia tego samego, co pfunkcja zaproponowana w pytaniu, początkowo zaimplementowana przez aitap i udoskonalona przez Scotta. (2) Czy możesz przekazać argumenty w ten sposób? ISTM, który make gizmo arg1 arg2jest równoważny make gizmo; make arg1; make arg2.
G-Man mówi „Przywróć Monikę”
1
(1) Być może moje założenie jest błędne, ale nie jest dla mnie jasne, że OP chce unikać używania ./w każdym katalogu . Moim zdaniem coś rozwija i po prostu musi ./fileczęsto uruchamiać wyprodukowany program . Naprawdę nie mogę myśleć o jakiejkolwiek innej sytuacji, w której można by często należy uruchomić plik lokalny, a jeśli nie jest uruchomiony to często nie chcesz pytać pytanie (powiedział, trudno nie niemożliwe ), (2) nie do końca , ale możesz przekazać argumenty z przepisu.
ihato,
(1) Myślę, że możemy się zgodzić, że motywacja PO i zakres jego pytania są niejasne. (2) Dzięki za link.
G-Man mówi „Przywróć Monikę”
3

Aby rozwinąć odpowiedź Zanny na temat tłumaczy (przepraszam, brak komentarza dla komentarza): „tłumacz” dla natywnych plików wykonywalnych (czyli binarnych plików ELF) jest dynamicznym modułem ładującym ( ld.so), ale zazwyczaj nie rozumie pożądanej składni:

$ /usr/lib/ld-linux-x86-64.so.2 program
program: error while loading shared libraries: program: cannot open shared object file
$ /usr/lib/ld-linux-x86-64.so.2 ./program
<program is launched>

(także, chyba że dowiązujesz symbolicznie ld.sodo swojej ścieżki, nadal będziesz musiał napisać /s)

bacondropped
źródło
To jest specyficzne dla Linuksa, prawda? Czy możesz wyjaśnić to więcej, dlaczego to działa? Myślałem, że jądro (Linux) zrobi parsowanie i zdecyduje, czy i jak uruchomić plik binarny, po to binfmt_miscjest.
phk
2
@phk Plik jest specyficzny dla Linuksa, ale koncepcja dynamicznego linkera / modułu ładującego nie jest. Na przykład FreeBSD ma swoje własne /libexec/ld-elf.so.1. W systemie Linux nie jest to tak proste, jak „decyzja o uruchomieniu pliku binarnego”: binfmt_miscwykrywa format pliku za pomocą magicznych liczb (ELF, skrypt shebang, CIL). Następnie binfmt_elfwywoływany jest moduł obsługi. Analizuje nagłówki i sekcje ELF; .interpsekcja zawiera ścieżkę dynamicznego modułu ładującego; ten moduł ładujący jest uruchamiany przez jądro, dokonuje relokacji i przeskakuje do _start. Na FreeBSD (nie jestem pewien co do innych) nie ma binfmt, ale zasada jest podobna do +/-.
bacondropped
1
@phk, dlaczego to działa - ld.sonie ma .interpi jest statycznie powiązane, co oznacza, że ​​nie potrzebuje innego dynamicznego linkera / modułu ładującego, aby rozwiązać swoje zewnętrzne symbole i wykonać matematykę relokacji.
Bacondropped
ISTR Solaris ma również coś równoważnego z tym.
G-Man mówi „Przywróć Monikę”
3

Jeśli wolno nam zacząć konfigurować

mkdir -p ~/.local/bin
cat > ~/.local/bin/x << 'EOF'
#!/bin/sh
N="$1"
shift
exec "./$N" "$@"
EOF
chmod a+x ~/.local/bin/x

Większość współczesnych dystrybucji zawiera już ~ / .local / bin w $ PATH (dodaj export PATH="$HOME/.local/bin:$PATH"do twojego, ~/.profilejeśli twój nie). Następnie możesz użyć x filedo uruchomienia ./file.

Nie próbuj definiować .polecenia. Polecenie . scriptdziała już scriptw bieżącej powłoce. Pozwala scriptto zdefiniować zmienne środowiskowe dla bieżącej powłoki.

sourcejedi
źródło
3
Myślę, że może tu być dobra sugestia, ale nie ma wyjaśnienia, co to robi. Mogłem to wypracować, ale niedoświadczony użytkownik nie miałby szans.
IMSoP,
Nie trzeba przesuwać 1 $. Właśnie exec "$@".
reinierpost
$ (ln -s /bin/ls my-ls && exec my-ls) # bash: exec: my-ls: not found
sourcejedi
(1) Nie ma takiej potrzeby shift $1; właśnie exec ./"$@". (2) Ponieważ mówisz o skrypcie powłoki, jest trochę bezcelowe / wprowadzające w błąd doradzanie ludziom, aby nie definiowali .polecenia, ponieważ niemożliwe jest utworzenie pliku o nazwie .. (Możliwe i bardzo niewskazane jest zdefiniowanie aliasu lub funkcji powłoki o nazwie ..)
Scott
1

Jeśli wolno nam tworzyć skrypty pomocnicze, możesz zrobić pomocnika, który doda PWD do ŚCIEŻKI, a następnie uruchom

. pathhelper    #adds pwd to path
file            #now it can be run without ./

Pozwala to uniknąć dodawania „.” do ścieżki i zanieczyszczając swój .profile każdą ścieżką, w której możesz chcieć coś uruchomić.

Możemy pójść o krok dalej, tworząc pomocnika, który uruchamia nową powłokę ze zmodyfikowaną ŚCIEŻKĄ. Jeśli bierze katalog jako parametr (używając domyślnie pwd), działałoby to tak, jakby pushdedytował ścieżkę. Być może będziesz musiał pamiętać, że wszelkie zmiany innych zmiennych środowiskowych zostaną utracone podczas wychodzenia z podpowłoki, ale w długo działającej powłoce twoja zmienna PATH nie będzie zaśmiecona. W zależności od przepływów pracy może to być korzystne.

:outer shell prompt$; subshellpathhelper    # launches a subshell with modified PATH
: subshell prompt $ ; file                  # in the subshell it can be run without ./

Ale myślę, że jeśli chce biegać z nim można siekać pushdi popdtak mogą zrobić te same modyfikacje ścieżki bez bez podpowłoce które stracą inne zmiany.

pushd --path ~/some/path/    # normal pushd plus adds target to path
file                         # it can be run without ./ until you popd

(Nie możesz zrobić tego samego, cdponieważ nie ma analogu do popd.)

Możesz także utworzyć dedykowaną parę pomocników, aby po prostu przesuwać i otwierać wpisy PATH. To, co działa najlepiej, zależy od wzorców użytkowania.

ShadSterling
źródło
Właściwie możesz zrobić coś takiego cd, ale jest to jeszcze dalej: Utwórz plik podobny do .dircmdsi zhakuj, cdaby polecenia zdefiniowane były ./.dircmdsniedostępne tuż przed przełączeniem i dostępne zaraz po przełączeniu.
ShadSterling
-1

Możesz używać . script.shskładni, o ile skrypt, który chcesz wykonać, znajduje się w bieżącym katalogu.

Możesz także prefiksować za pomocą interpretera, np. Sh lub bash. przykład:bash script.sh

UltimateByte
źródło
8
. script.shzepsuje się, jeśli skrypt zawiera exit, ma nieoczekiwane efekty, np. jeśli przedefiniował PATH „tymczasowo”; działa również tylko w przypadku skryptów dla bieżącej powłoki
sourcejedi
@sourcejedi Jeśli chodzi o exitto, że możesz umieścić go w nawiasach, tj. podpowłokę, ale to prawda, nadal byłoby to tylko dla skryptów w tej samej powłoce.
phk
Pytanie brzmi „plik wykonywalny”. Nie będą działać dla binarnego pliku wykonywalnego; tylko dla skryptu. A twój drugi akapit powiela odpowiedź Zanny .
Scott,
Cóż, moje złe, głównie wykonuję i dev bash, więc założyłem, że rozmawiamy o skryptach bash :)
UltimateByte
Nie tylko dla skryptu, ale tylko dla skryptu Bash.
Oskar Skog