Non c'è alcun comando 'sudo' in Cygwin


41

Perché non c'è alcun comando sudo in Cygwin , gli script con cui voglio eseguire falliscono

./install.sh: line N: sudo: command not found

Qual è il modo standard per aggirare questo? Modificare gli script da rimuovere sudo? Ottenere uno sudostrumento simile a Windows?


@dotancohen, spero di aver scelto quello giusto.
Jason Sundram,

Mi sembra una buona soluzione! Il supporto di Cygwin è sicuramente migliorato negli ultimi cinque anni!
dotancohen,


@ Benj, mi chiedo perché anche questa domanda non sia stata migrata qui.
Jason Sundram,

@JasonSundram davvero. Fammi sapere se la risposta viene spostata, quindi aggiornerò il collegamento.
Benj,

Risposte:


8

Ho scritto il (piuttosto semplice) TOUACExt per SUDO per CygWin , un'automazione di script shell pre-beta che si avvicina al comportamento della classica sudo per Linux:

  • Apre e chiude automaticamente sudoserver.py quando necessario.
  • Richieste prompt elevazione UAC .

L'installazione richiede la copia dei quattro .shscript in una directory del percorso, creando un alias e solo alcuni passaggi dettagliati nel thread.

I risultati : si digita un singolo sudo YourCommande si ottiene l'output di esso, senza doversi preoccupare del resto del processo.


35

Un modo è quello di creare un falso comando "sudo" con il seguente contenuto:

#!/usr/bin/bash

"$@"

Ciò consentirà install.shdi continuare, perché sudo è stato trovato.

Questo non eleva i privilegi come fa il vero sudo. Se hai davvero bisogno di privilegi elevati, avvia cygwin shell con da un account con privilegi di amministratore (XP) o fai di nuovo clic su cygwin.bat e "esegui come amministratore" (Vista, Win7)


5
Solo per curiosità da qualcuno che non parla fluentemente bash: perché funziona? La manpage non dice nulla sul $@fare qualcosa di sudosimile. Invece sono solo tutti gli argomenti della sceneggiatura. E le citazioni intorno non sarebbero superflue in quel caso? Altrimenti, se lo facessi sudo foo bar, prova a eseguirlo "foo bar"come un singolo comando che probabilmente non esiste, data la paura irrazionale degli spazi su sistemi simili a UNIX.
Joey,

7
@Johannes: "$@"(se racchiuso tra virgolette doppie) funziona in modo diverso da "$*": si espande in una parola separata per ogni variabile di posizione. Esempio: Se $1 == "foo bar"e $2 == "baz", allora "$@"è "foo bar" baz- una parola per ciascun parametro (diversamente da "$*", che risulta "foo bar baz"come una parola). Vedere il manuale di bash, sezione Parametri , sottosezione Parametri speciali . Il risultato finale della sceneggiatura di Peon è che esegue i suoi argomenti esattamente come sono stati passati.
gravità

1
Ah ok. E da dove viene la sudoparte? Lo snippet sopra non fa nulla in remoto in quella direzione, giusto?
Joey,

2
@Johannes: In Unix, un vero utente eleverebbe i sudoprivilegi da mortale a rootprima di eseguire il comando. In Cygwin non esiste nulla del genere, quindi il falso copione di Peon (che dovresti nominare sudo) esegue semplicemente il comando direttamente senza modificarne i privilegi. (Ciò significa che potrebbe essere necessario eseguire ./install.shcome amministratore.)
Grawity

2
@grawity: runasdovrebbe funzionare, non dipende dall'UAC e richiede una password da sola. Ero solo confuso perché la sceneggiatura nella risposta apparentemente non faceva ciò che il nome implicava e presumevo fosse l'obiettivo. Scusate la mia stupidità ;-)
Joey,

21

Ho trovato la risposta sulla mailing list di Cygwin . Per eseguire commandcon privilegi elevati in Cygwin, precedere il comando in cygstart --action=runasquesto modo:

$ cygstart --action=runas command

Questo aprirà una finestra di dialogo di Windows che richiede la password dell'amministratore ed eseguirà il comando se viene inserita la password corretta.

Questo è facilmente scriptato, purché ~/binsia nel tuo percorso:

$ cat ~/bin/sudo
#!/usr/bin/bash
cygstart --action=runas "$@"

$ PATH=$HOME/bin:$PATH
$ chmod +x ~/bin/sudo
$ sudo elevatedCommand

Testato su Windows 8 a 64 bit.


5
Il problema con il cygstartmetodo è che funziona solo per comandi / programmi Windows. Non si può fare sudo ls. SUDO per CygWin è pulito, ma manca ancora un buon sudocomando.
Sopalajo de Arrierez,

Grazie Sopalajode. In quale situazione è necessario utilizzare sudo lsin Cygwin?
dotancohen,

3
Oh, no, @Dotancohen, era solo un esempio. È possibile utilizzare sudoCygWin per eseguire qualsiasi comando Windows o CygWin. È molto utile per me Ma il metodo più pratico che ho trovato è questo wrapper di script per SUDO per CygWin che ho sviluppato: superuser.com/questions/741345/… (ancora in beta, ma sembra funzionare). Con esso puoi ordinare comodamente cose come sudo net start vncserver.
Sopalajo de Arrierez,

@SopalajodeArrierez: È assolutamente fantastico! Grazie per il post e il link.
dotancohen,

curiosamente, questo si spoglia /bine /usr/bindal PATH. Invoca con successo emacs: ShellExecute(NULL, "runas", "C:\cygwin64\bin\emacs-w32.exe", "(null)", "(null)", 1)ma poi emacs non riesce a trovare lsad esempio M-x dired, anche dopo aver ripristinato interattivamente il PATH usando (setenv ...). C'è un problema relativo ai percorsi attendibili qui?
BaseZen

5

Sulla base della risposta di dotancohen sto usando un alias:

alias sudo="cygstart --action=runas"

Funziona come un incantesimo per programmi esterni (non con shell incorporate, però):

sudo chown User:Group <file>

3

Sudo (Elevate) per Windows ™

Faccio molto lavoro sulla riga di comando in Windows ™.

In Cygwin stesso credo che tu possa eseguire un comando di root con su -c /the/cmdsudo stesso all'interno del file system di Windows ™ elevando le autorizzazioni dell'utente dalla riga di comando. Se sei un amministratore, funzionerà benissimo per te. Altrimenti, usa runas e ottieni il pass admin;).

Ora non ricordo dove abbiamo trovato questo codice ma eccolo qui. Spero possa essere d'aiuto.

A proposito, il pacchetto che usiamo per compilare questo era gcc-mingw32.

$ i586-mingw32msvc-gcc sudo.c -o sudo.exe
# Put sudo.exe in /usr/bin or in your windows path (%homedrive%\windows)
#example:
$ sudo vi /cygdrive/c/windows/system32/drivers/etc/hosts

/**
* (sudo for Windows™)
* @filename sudo.c
*/
#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
#include <shellapi.h>
#include <wchar.h>


LPWSTR *mergestrings(LPWSTR *left, LPCWSTR right)
{
    size_t size = ( 1 + lstrlen(*left) + lstrlen(right) ) * sizeof(LPWSTR*);
    if ( *left ) {
        LPWSTR leftcopy = _wcsdup(*left);
        *left = (LPWSTR)realloc(*left, size);
        *left = lstrcpy(*left, leftcopy);
        *left = lstrcat(*left, right);
        free( leftcopy );
    }
    else
        *left = _wcsdup(right);
    return left;
}


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, LPSTR lpcommand, int nShowCmd)
{
    DWORD result = 0x2a;
    LPWSTR *argv = NULL;
    int argc = 0;
    if ( argv = CommandLineToArgvW(GetCommandLineW(), &argc) ) {
        if ( argc < 2 ) {
            LPWSTR usagemsg = NULL;
            usagemsg = *mergestrings(&usagemsg, argv[0]);
            usagemsg = *mergestrings(&usagemsg, TEXT(" <command_to_run> [arguments]"));
            MessageBox(NULL, usagemsg, TEXT("Usage:"), MB_OK | MB_ICONEXCLAMATION );
            LocalFree( argv );
            free( usagemsg );
            return ERROR_BAD_ARGUMENTS;
        }
        else {
            LPWSTR command = argv[1];
            LPWSTR arguments = NULL;
            int c;
            for ( c = 2; c < argc; c++ ) {
                arguments = *mergestrings(&arguments, argv[c]);
                arguments = *mergestrings(&arguments, TEXT(" "));
            }
            result = (DWORD)ShellExecute(NULL, TEXT("runas"), command, arguments, NULL, SW_SHOWNORMAL);
            LocalFree( argv );
            if ( arguments )
                free( arguments );
            switch ( result )
            {
                case 0:
                    result = ERROR_OUTOFMEMORY;
                    break;

                case 27:
                case 31:
                    result = ERROR_NO_ASSOCIATION;
                    break;

                case 28:
                case 29:
                case 30:
                    result = ERROR_DDE_FAIL;
                    break;
                case 32:
                    result = ERROR_DLL_NOT_FOUND;
                    break;
                default:
                    if ( result > 32 )
                        result = 0x2a;
            }
        }
    }
    else
        result = GetLastError();

    if (result != 0x2a) {
        LPWSTR errormsg = NULL;
        FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
                      NULL, result, 0, (LPWSTR)&errormsg, 0, NULL);
        MessageBox(NULL, errormsg, TEXT("Error:"), MB_OK | MB_ICONERROR);
        LocalFree( errormsg );
        return result;
    }
    else
        return NO_ERROR;
}

5
Questo codice è terribile. È pieno di errori come non controllare il valore restituito da realloc () prima di dereferenziare o scrivere sizeof (LPWSTR *) invece di sizeof (* LPWSTR) in cui LPWSTR sembra essere un tipo di puntatore e si vuole recuperare la dimensione di un carattere, non la dimensione del puntatore. Inoltre, non è del tutto chiaro perché, ad esempio, il caso 29 porti a ERROR_DDE_FAIL. Puoi concludere dal codice perché? Non posso e immagino che anche chiunque altro non possa farlo. Per favore, non pubblicare tale codice in futuro.

4
@Mattew: per favore, in futuro, aiuta la community pubblicando una versione ripulita dello snippet di codice che non ti piace.
Erik Allik,

Il codice non dovrebbe essere su superutente. Mettilo su codereview.se e collegalo da qui.
Ben Voigt,

@ user185282: punti positivi. Ho votato in negativo la risposta.
indimenticabile il

Caro tao: hai scritto "Non ricordo dove abbiamo trovato questo codice". Hai scritto questo codice o lo ha scritto qualcun altro?
indimenticabile il

2

Un leggero miglioramento sul falso script di sudo di Peon :

#!/bin/sh
# Drop any option arguments.
while [[ $# -ge 0 && $1 = -* ]]; do
  shift
done

"$@"

Questo script elimina automaticamente tutte le opzioni passate a sudo ed esegue il comando (senza in realtà elevare i privilegi). Eliminare le opzioni migliora leggermente la compatibilità. Uno script wrapper più completo dovrebbe effettivamente analizzare le opzioni allo stesso modo di sudo.

Invece di provare a sostituire sudo con un wrapper che lo fa cygstart --action=runas "$@", basta usare questo semplice wrapper falso sudo ed eseguire lo script di installazione stesso (o qualunque cosa tu stia cercando di eseguire che usi sudo) con privilegi elevati.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.