Przekierowanie standardowego pliku do pliku, na którym nie masz uprawnień do zapisu


113

Podczas próby zmodyfikowania pliku bez uprawnień do zapisu pojawia się błąd:

> touch /tmp/foo && sudo chown root /tmp/foo
> echo test > /tmp/foo
zsh: permission denied: /tmp/foo

Sudoing nie pomaga, ponieważ uruchamia polecenie jako root, ale powłoka obsługuje stdout przekierowujący i otwiera plik tak jak ty:

> sudo echo test > /tmp/foo
zsh: permission denied: /tmp/foo

Czy istnieje prosty sposób przekierowania standardowego pliku do pliku, do którego nie masz uprawnień do zapisu, oprócz otwarcia powłoki jako root i manipulowania plikiem w ten sposób?

> sudo su
# echo test > /tmp/foo

2
Odpowiedz na podobne pytanie od StackOverflow stackoverflow.com/questions/82256/…
Cristian Ciupitu

jak możesz nie mieć uprawnień do pliku, który sam utworzyłeś w tmp? czy to z powodu umask?
k961

@ k961 Kiedyś chownzmieniałem właściciela; to tylko przykład
Michał Mrożek

Odpowiedzi:


116

Tak, używając tee. Tak się echo test > /tmp/foostaje

echo test | sudo tee /tmp/foo

Możesz także dołączyć ( >>)

echo test | sudo tee -a /tmp/foo

27
Tee również wyświetli wyjście standardowe; czasami nie chcesz, aby zawartość wypełniała ekran. Aby to naprawić, zróbecho test | sudo tee /tmp/foo > /dev/null
Shawn J. Goff,

Jak to zrobisz z heredoc?
JohnDoea,

26

Aby zamienić zawartość pliku na wynik echo(np. >Operator przekierowania powłoki).

echo test | sudo dd of=/tmp/foo

Aby zapisać do pliku (na początku możesz używać seekwyjścia z różnymi przesunięciami) bez obcinania (jak 1<>operator powłoki Bourne'a):

echo test | sudo dd of=/tmp/foo conv=notrunc

Aby dołączyć do pliku (jak >>) za pomocą GNU dd:

echo test | sudo dd of=/tmp/foo oflag=append conv=notrunc

Zobacz także GNU dd, conv=exclaby uniknąć blokowania istniejącego pliku (jak set -o noclobberw przypadku powłok POSIX), a conv=nocreatna odwrót (aktualizuj tylko istniejący plik).


sprytny! zmniejsza to potrzebę zrobienia, echo test | sudo tee /tmp/foo >/dev/nullaby odrzucić dane wyjściowe.
Adam Katz

2
Być może będę musiał to cofnąć; ddjest niewiarygodne, chyba że używasz niejasnych opcji tylko GNU iflag=fullblock oflag=fullblock, które usuwają elegancję tej odpowiedzi. Będę się trzymać tee.
Adam Katz

5
dd jest niezawodny przy nieokreślonym bs = 1
umeboshi

2
@umeboshi Ale wiarygodny tylko wtedy, gdy masz wystarczające doświadczenie, aby dokładnie wiedzieć, co robisz. Bo ddmoże być dość niebezpieczny (jeśli nie mówiąc: niszczący), jeśli popełniony zostanie tylko niewielki błąd. Tak więc dla nowych użytkowników wolałbym teemetodę przebywania na bezpiecznym brzegu.
składniaerror

1
@AdamKatz, w przypadku dd of=filesamego (bez count/ skip...), jest niezawodny. iflag=fullblocknie jest potrzebne, ponieważ tutaj ddzapisuje na wyjściu to, co przeczytał na wejściu. Nie ma znaczenia, czy nie były to pełne bloki.
Stéphane Chazelas,

12

tee jest prawdopodobnie najlepszym wyborem, ale w zależności od twojej sytuacji coś takiego może wystarczyć:

sudo sh -c 'echo test > /tmp/foo'

1
3 problemy: evalzamiast prostego sh -c; -i, co zmieni twój działający katalog; uruchomienie całej komendy jako root, co może zmienić jej zachowanie lub wprowadzić niepotrzebne ryzyko. dlaczego to kiedykolwiek zyskało aprobatę?

4
nie zrobiłeś tego, ale jest to mylące, ogólnie złe i może nawet niebezpieczne.

5

Chociaż zgadzam się, że | sudo teejest to sposób kanoniczny, czasami sed (tutaj przy założeniu GNU sed) może działać:

cat sudotest 
line 1

sudo sed -i '1iitest' sudotest && cat sudotest 
itest
line 1

sudo sed -i '$aatest' sudotest && cat sudotest 
itest
line 1
atest

-imodyfikuje plik na miejscu. 1ioznacza wstaw przed wierszem 1. $aoznacza dołącz po ostatnim wierszu.

Lub skopiuj do xclipboard:

somecommand | xclip
sudo gedit sudotest
move cursor to desired place, click middle mouse button to insert, save

1
Jest to sformułowane jak starożytna chińska zagadka. Nie widzę, żeby zrozumieć, skąd tyle głosów poparcia. ( hrmph )
składniaerror

1
@syntaxerror: Sir, przepraszam, nie jestem rodzimym językiem angielskim. Jeśli określisz, co jest dla ciebie niejasne, mógłbym spróbować poprawić swoją odpowiedź. W porównaniu z 65 głosami pozytywnymi dla Gerta, 4 również nie wydaje się tak dużym głosowaniem, nie sądzisz?
użytkownik nieznany

Byłbym bardzo zadowolony z 4 :-D Twój angielski wcale nie jest zły. Jest po prostu sformułowany w rodzaju zwięzłego nerdspe. Zgaduję, że jesteś programistą. Koderzy między sobą doskonale zrozumieją się w ten sposób, ale niekodujący musi pomyśleć, że to brzmi jak ... jak już powiedziano.
składniaerror

Zauważ, że sed -itak naprawdę nie modyfikuje pliku na swoim miejscu - tworzy plik tymczasowy i zmienia nazwę podczas wychodzenia. Więc nie będziesz w stanie zrobić czegoś takiego jak tail -f ...na oryginalnym pliku i zobaczyć, jak dane wyjściowe są używane sed -i ...podczas działania potoku
Andrew Henle

@AndrewHenle: Tak, ponieważ rozmiar może zostać zwiększony lub zmniejszony, a ponieważ prawdopodobnie ma to miejsce w przypadku większości wywołań sed, a nie można nawet - afaik - pisać w tej samej lokalizacji na dyskach SSD, jest to tylko pseudo operacja „na miejscu” . Czy jako osoba, która nie zna języka angielskiego, mogę poprosić o krótkie wyrażenie, które nie jest tak źle interpretowane? Czy -i creates a new file of same namemoże jest coś bardziej kompaktowego? Chyba lubię in place, bo to wyjaśnia i. Strona gnu-sed również nazywa to na miejscu, a długa flaga jest --in-place.
użytkownik nieznany

2

Kopałem sobie w głowie pomysły na podobny problem i wymyśliłem następujące rozwiązania:

  • sudo uncatgdzie uncatjest program, który czyta standardowe dane wejściowe i zapisuje je do pliku o nazwie podanej w wierszu poleceń, ale jeszcze nie napisałem uncat.

  • sudocatwariant sudoedit, którego jeszcze nie napisałem, który czyści sudo catlub sudo uncat.

  • lub tę małą sztuczkę korzystania sudoeditz EDYTORA, który jest skryptem powłoki

    #!/bin/sh
    # uncat
    cat > "$1"

    które mogą być powoływane jako albo |sudo ./uncat filealbo | EDITOR=./uncat sudoeditale ma ciekawe efekty uboczne.


catpobiera listę plików do con kota inate zatem UNCAT powinien wziąć listę plików do un con kota inate do. Będzie musiał użyć magii, aby zdecydować, ile umieścić w każdym pliku. Alternatywna nazwa obejmują dog, to-file, redirect.
ctrl-alt-delor

Nie mogę wymyślić żadnego powodu, dla którego miałbym chcieć uncat, gdybym miał tee.
Wildcard

1
Cóż, teema tę trywialną wadę, że zapisuje swoje standardowe wejście na standardowe wyjście - co jest trywialnie zmniejszone przez przekierowanie standardowego wejścia na /dev/null. Inne alternatywy to dd of=/tmp/foo(wspomniane w innej odpowiedzi), która zapisuje informacje o statusie do stderr i cp /dev/stdin /tmp/foo.
Scott

1

Użyj gąbki z pakietu moreutils. Ma tę zaletę, że nie pisze na standardowe wyjście.

echo test | sudo sponge /tmp/foo

Użyj opcji -a, aby dołączyć do pliku zamiast nadpisywać go.


1
Nie jestem pewien, do jakiej korzyści nie ma pisania na standardowe prezenty, ale możesz po prostu przekierować wyjście, /dev/nulljeśli byłby to problem
Michael Mrozek

1
Oczywiście mogę przekierować do / dev / null, ale polecenie jest łatwiejsze do odczytania i pisania bez przekierowania. Zaletą braku pisania na standardowe wyjście jest to, że mój terminal nie jest pełen śmieci.
Hontvári Levente

1
Nie instalowałbym pakietu, by oszczędzić przekierowania, ale regularnie używam gąbki, więc już tam jest.
Hontvári Levente

0

Błąd pochodzi z kolejności, w jakiej powłoka wykonuje różne czynności.

Przekierowanie jest obsługiwane przed uruchomieniem powłoki sudo, a zatem odbywa się za zgodą użytkownika, nad którym obecnie pracujesz. Ponieważ nie masz uprawnień do zapisu, aby utworzyć / skrócić cel przekierowania, otrzymujesz permission deniedbłąd z powłoki.

Rozwiązaniem jest zagwarantowanie, że plik wyjściowy zostanie utworzony zgodnie z tożsamością podaną przez użytkownika sudo, np . tee:

$ generate_output | sudo tee target_file
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.