Exécutez une ligne de commandes avec un sudo

21

Par exemple, si je veux créer un fichier et saisir du texte sur une seule ligne, je peux rediriger la sortie dans un fichier en utilisant l' >opérateur:

echo "something" > /path/foobar

mais si je n'ai pas accès au dossier /path/et que j'ai besoin des privilèges sudo, comment puis-je obtenir cette même commande en tant qu'utilisateur normal avec des droits sudo?

j'ai essayé

sudo echo "something" > /path/foobar

mais cela ne fonctionne pas, car le sudo ne compte que editpour la partie droite
du>

Bien sûr, je pourrais devenir root avant avec sudo suou utiliser à la teeplace:

echo "something" | sudo tee /path/foobar

Mais je voudrais trouver une solution où je peux travailler avec la dernière ligne en remplacement via

sudo !!

N'y a-t-il pas un moyen de «recycler» la dernière ligne et de simplement l'ajouter sudodevant?

rubo77
la source
1
redondance possible de la redirection
lequel
Ce n'est pas un doublon. J'ai extrait le vrai Qeustion et changé le titre. Maintenant, c'est ce que je recherche vraiment
rubo77
Il a certainement été un double, mais il est un peu différent. Il me semble que vous avez réécrit la question à la lumière de la réponse de Boogy, ce qui est bien - c'est une bonne réponse. J'ai rétracté mon vote serré, mais c'est toujours inévitable (les gens votent souvent automatiquement une fois qu'une question est dans la file d'attente étroite sans faire attention au problème): adresse un commentaire @goldilocks quand il est fermé et je voterai pour rouvrir . Vous pouvez également plaider votre cause dans le chat une fois que cela se produit.
goldilocks
Voir aussi Comment puis-je alias sudo !!?
Gilles 'SO- arrête d'être méchant'

Réponses:

13

Vous ne pouvez pas simplement rester sudodevant une commande shell, vous devez invoquer un shell pour évaluer à nouveau cette commande (faire des choses comme développer des variables, ouvrir des fichiers pour des opérateurs de redirection, etc.). Donc, c'est

sudo bash -c !!

sauf que cela ne fonctionne pas tout à fait, car !!interpole le texte de la commande précédente, les caractères spéciaux et tout. Vous devez récupérer le texte de la commande sous forme de chaîne et le transmettre comme argument à sh. Heureusement, la fonction fcintégrée de bash vous permet de le faire¹.

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

Ou même, pour être sûr d'invoquer la même version de bash en cours d'exécution:

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

Notez que puisque la commande est exécutée dans un processus shell séparé, elle hérite des variables d'environnement (uniquement celles qui les sudoconservent, l'esprit), mais pas des variables internes du shell. Les options du shell (par exemple kshglob) et d'autres paramètres commenceront par défaut.

La même commande² fonctionne dans zsh et ksh, bien que ATT ksh93 nécessite que le firstet le lastnombre soient passés à fc³ (qui fonctionne également dans bash, zsh et pdksh / mksh):

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

Utiliser $0pour désigner l'exécutable du shell en cours d'exécution ne fonctionne que si le shell a été appelé via $ PATH et que $ PATH n'a pas changé, ou via un chemin absolu.

Voici une autre méthode dans zsh qui est légèrement plus claire mais plus longue:

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

Un dernier mot d'avertissement: sudoconcerne les commandes potentiellement dangereuses. Ne le rendez pas trop facile à utiliser!

¹ Il y a un espace supplémentaire au début et la substitution de commandes supprime les nouvelles lignes à la fin, mais la syntaxe du shell s'en fiche.
² Je ne pense pas que zsh ou ksh aient quelque chose comme bash $BASH; $0ne fonctionne que lorsqu'il s'agit d'un chemin absolu, ou lorsqu'il ne contient pas de barre oblique et que le chemin de recherche de commande n'a pas changé.
³ est un alias pour dans ATT ksh mais c'est tout aussi bien. fchist

Gilles 'SO- arrête d'être méchant'
la source
9

Si vous voulez refaire la même commande avec sudo !! après avoir fait une commande comme celle-ci:

echo "something">/path/file

Vous utilisez la syntaxe globale de remplacement pour rappeler la commande:

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

Utilisez un espace après le paramètre -a .

C'est l'équivalent de sudo !! mais vous aide à contourner les restrictions sudo pour les <et>. Parce que sudo ne vous permet pas d'utiliser [<,>].


Pour contourner les restrictions sudo en général pour les redirections, vous pouvez l'utiliser comme ceci:

echo "something" | sudo tee myfile

La commande tee vous permettra de lire à partir de l'entrée standard et d'écrire sur la sortie standard et les fichiers

Si vous souhaitez répéter la commande et ajouter un texte au fichier, la commande tee a l' option -a pour l'ajout. Vous pouvez donc rappeler la commande avec

sudo !!

et le texte sera ajouté dans le fichier

exemple:

echo "something" | sudo tee -a /path/file
sudo !!
Boogy
la source
belle solution, mais un peu difficile à mémoriser. Comment puis-je créer un alias pour une commande en utilisant !! rappeler la dernière commande ?
rubo77
est-ce -avraiment nécessaire? >écrasera un fichier, tee -aajoutera, ce qui serait>>
rubo77
3

Cela semble être aussi simple que 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
la source
3
Si la commande utilise des guillemets, ce n'est pas nécessairement équivalent. Considérez echo "foo bar"ce qui deviendrait sh -c "echo "foo bar""ce qui s'imprimerait fooau lieu de foo bar.
godlygeek
J'ai essayé à la sudo sh -c '!!'place si votre commande mais cela ne fonctionne pas non plus
rubo77
Et si votre commande utilisait des guillemets simples et doubles? Ou des guillemets doubles et des extensions variables? Si l'utilisateur le faisait: a=bet puis echo "$a" >fileet puis sudo sh -c '!!'il se développerait sur sudo sh -c 'echo $a >file'lequel imprimerait une ligne vide au lieu de bdans file.
godlygeek
Alors peut-être existe-t-il une solution encore meilleure?
rubo77
1
Je ne pense pas qu'il existe de solution qui fonctionnera à 100% sans que vous ayez à modifier la commande. Utiliser sudopour obtenir un shell racine, puis copier et coller la commande serait le plus proche, mais échoue si la commande devait utiliser des variables définies dans votre shell non root. L'utilisation sudo sh -c "!!"fonctionne bien pour les commandes simples, mais est lourde pour les commandes complexes. Je pense que le meilleur conseil est de ne pas s'attendre à ce qu'il y ait une commande qui fonctionnera à 100% du temps - apprenez quelques solutions possibles et appliquez-les quand elles conviennent le mieux.
godlygeek