Wykonaj wiersz poleceń za pomocą jednego sudo

21

Na przykład, jeśli chcę utworzyć plik i wprowadzić tekst w jednym wierszu, mogę przekierować dane wyjściowe do pliku za pomocą >operatora:

echo "something" > /path/foobar

ale jeśli nie mam dostępu do folderu /path/i potrzebuję uprawnień sudo, jak mogę wykonać to samo polecenie, co zwykły użytkownik z uprawnieniami sudo?

próbowałem

sudo echo "something" > /path/foobar

ale to nie działa, ponieważ sudo liczy się tylko dla osób edit, ale nie dla prawej części
z>

Jasne, mógłbym zostać rootem przed sudo sulub użyć teezamiast tego:

echo "something" | sudo tee /path/foobar

Chciałbym jednak znaleźć rozwiązanie, w którym będę mógł pracować z ostatnią linią jako zamiennikiem przez

sudo !!

Czy nie ma sposobu na „przetworzenie” ostatniego wiersza i dodanie go sudoz przodu?

rubo77
źródło
To nie jest duplikat. Wyodrębniłem prawdziwe Qeustion i zmieniłem tytuł. Teraz tego naprawdę szukam
rubo77,
Z pewnością był to duplikat, ale teraz jest nieco inny. Wydaje mi się, że przepisałeś pytanie w świetle odpowiedzi Boogy'ego, co jest w porządku - to dobra odpowiedź. Cofnęłam swój głos, ale nadal jest on nieunikniony (ludzie często głosują automatycznie, gdy pytanie znajduje się w kolejce, nie zwracając uwagi na problem): skieruj komentarz @goldilocks, gdy zostanie zamknięty, a ja głosuję, aby ponownie otworzyć . Możesz również powołać się na swoją sprawę na czacie, gdy to się stanie.
goldilocks
Zobacz także Jak mogę alias sudo !!?
Gilles „SO- przestań być zły”

Odpowiedzi:

13

Nie możesz po prostu sudostać przed poleceniem powłoki, musisz wywołać powłokę, aby ponownie ocenić to polecenie (robiąc takie rzeczy, jak rozszerzanie zmiennych, otwieranie plików dla operatorów przekierowania itp.). Więc to jest

sudo bash -c !!

poza tym, że to nie do końca działa, ponieważ !!interpoluje tekst poprzedniego polecenia, znaków specjalnych i wszystkich innych. Musisz pobrać tekst polecenia jako ciąg znaków i przekazać go jako argument do sh. Na szczęście fcwbudowane bash pozwala ci to zrobić¹.

sudo bash -c "$(fc -ln -1)"

Lub nawet, aby mieć pewność, że uruchomisz tę samą wersję bash, która jest obecnie uruchomiona:

sudo "$BASH" -c "$(fc -ln -1)"

Zauważ, że ponieważ polecenie jest wykonywane w osobnym procesie powłoki, dziedziczy zmienne środowiskowe (tylko te, które sudozachowują, pamiętaj), ale nie wewnętrzne zmienne powłoki. Opcje powłoki (np. kshglob) I inne ustawienia zostaną uruchomione domyślnie.

To samo polecenie² działa w zsh i ksh, chociaż ATT ksh93 wymaga, aby zarówno firstand, jak i lastliczba zostały przekazane do fc³ (co działa również w bash, zsh i pdksh / mksh):

sudo zsh -c "$(fc -ln -1)"
sudo ksh -c "$(fc -ln -1 -1)"
sudo "$0" -c "$(fc -ln -1 -1)"

Użycie $0oznaczenia pliku wykonywalnego działającej powłoki działa tylko wtedy, gdy powłoka została wywołana przez $ PATH, a $ PATH nie uległa zmianie lub przez ścieżkę bezwzględną.

Oto kolejna metoda w Zsh, która jest nieco jaśniejsza, ale dłuższa:

sudo zsh -c $history[$[HISTCMD-1]]

Ostatnie słowo ostrzeżenia: sudodotyczy potencjalnie niebezpiecznych poleceń. Nie rób tego zbyt łatwo z niego korzystać!

¹ Na początku jest trochę białych spacji, a podstawianie poleceń usuwa nowe linie na końcu, ale składnia powłoki nie dba o to.
² Nie sądzę, aby Zsh lub Ksh miały coś takiego jak bash $BASH; $0działa tylko wtedy, gdy jest to ścieżka bezwzględna lub gdy nie zawiera ukośnika, a ścieżka wyszukiwania poleceń nie uległa zmianie.
³ jest pseudonimem dla ATT ksh, ale to jest równie dobre. fchist

Gilles „SO- przestań być zły”
źródło
9

Jeśli chcesz powtórzyć to samo polecenie w sudo !! po wykonaniu następującego polecenia:

echo "something">/path/file

Używasz globalnej składni zastępowania do przywołania polecenia:

!!:gs/>/|sudo tee -a /

Użyj spacji po parametrze -a .

Jest to odpowiednik sudo !! ale pomaga ominąć ograniczenia sudo dla <i>. Ponieważ sudo nie pozwala na użycie [<,>].


Aby ogólnie ominąć ograniczenia sudo dotyczące przekierowań, możesz użyć tego w następujący sposób:

echo "something" | sudo tee myfile

Polecenie tee pozwala na odczyt ze standardowego wejścia i zapis na standardowe wyjście i pliki

Jeśli chcesz powtórzyć polecenie i dołączyć tekst do pliku, polecenie tee ma opcję -a do dołączenia. Możesz więc przywołać polecenie za pomocą

sudo !!

a tekst zostanie dołączony do pliku

przykład:

echo "something" | sudo tee -a /path/file
sudo !!
Boogy
źródło
fajne rozwiązanie, ale trudne do zapamiętania. Jak mogę utworzyć alias dla polecenia za pomocą !! przypomnieć sobie ostatnie polecenie ?
rubo77
czy -anaprawdę jest potrzebny? >nadpisze plik, tee -adołączy, który byłby>>
rubo77
3

Wydaje się to tak proste, jak sudo sh -c "!!":

$ cd /
$ echo hello > foo
bash: foo: Permission denied
$ sudo sh -c "!!"
sudo sh -c "echo hello > foo"
$ ls -l foo
-rw-r--r-- 1 root root 6 Jun 20 16:21 foo
deltab
źródło
3
Jeśli polecenie użyło cudzysłowu, niekoniecznie musi to być równoważne. Zastanów się, echo "foo bar"który stałby się, sh -c "echo "foo bar""który po prostu wydrukowałby foozamiast foo bar.
godlygeek
Próbowałem sudo sh -c '!!'zamiast tego, jeśli twoje polecenie, ale to też nie działa
rubo77,
Co wtedy, jeśli twoje polecenie użyło zarówno pojedynczego, jak i podwójnego cudzysłowu? A może podwójne cudzysłowy i zmienne rozszerzenia? Jeśli użytkownik zrobił: a=bi wtedy echo "$a" >filei wtedy sudo sh -c '!!'rozwinąłby się do sudo sh -c 'echo $a >file'tego, by wydrukować pustą linię zamiast bdo file.
godlygeek
Więc może jest jakieś lepsze rozwiązanie?
rubo77
1
Nie sądzę, aby istniało jakieś rozwiązanie, które działałoby w 100% bez konieczności modyfikowania polecenia. Użycie sudodo uzyskania powłoki roota, a następnie skopiowanie i wklejenie do niej polecenia byłoby najbliższe, ale nie powiedzie się, jeśli polecenie ma używać zmiennych ustawionych w powłoce innej niż root. Używanie sudo sh -c "!!"działa dobrze dla prostych poleceń, ale jest obarczone złożonymi. Myślę, że najlepszą radą jest, aby nie oczekiwać, że będzie jakieś polecenie, które zadziała w 100% przypadków - poznaj kilka możliwych rozwiązań i zastosuj je, kiedy najlepiej pasuje.
godlygeek