Não há comando 'sudo' no Cygwin


41

Como não há comando sudo no Cygwin , os scripts que eu quero executar falham

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

Qual é a maneira padrão de contornar isso? Editando os scripts para remover sudo? Obtendo alguma sudoferramenta semelhante ao Windows?


@ Dotancohen, espero ter escolhido o caminho certo.
Jason Sundram

Parece uma boa solução para mim! O suporte da Cygwin certamente melhorou nos últimos cinco anos!
dotancohen


@ Benj, eu me pergunto por que essa pergunta não foi migrada aqui também.
Jason Sundram

@JasonSundram de fato. Deixe-me saber se a resposta foi movida; em seguida, atualizarei o link.
214 Benj

Respostas:


8

Eu escrevi o (bastante simples) TOUACExt for SUDO para CygWin , uma automação de script de shell pré-beta que aborda o comportamento do clássico sudo para Linux:

  • Abrir e fechar automaticamente sudoserver.py quando necessário.
  • Solicita o prompt de elevação do UAC .

A instalação requer a cópia dos quatro .shscripts para algum diretório de caminho, criando um alias e apenas mais algumas etapas detalhadas no encadeamento.

Os resultados : você digita um único sudo YourCommande obtém a saída dele, sem ter que se preocupar com o resto do processo.


35

Uma maneira é criar um comando "sudo" falso com o seguinte conteúdo:

#!/usr/bin/bash

"$@"

Isso permitirá install.shque continue, porque o sudo foi encontrado.

Isso não eleva privilégios como o real sudo. Se você realmente precisa de privilégios elevados, inicie o cygwin shell com uma conta com privilégios administrativos (XP) ou clique com o botão direito do mouse em cygwin.bat e "execute como administrador" (Vista, Win7)


5
Apenas por curiosidade de alguém que não fala fluentemente bash: Por que isso funciona? A página de manual não diz nada sobre como $@fazer algo sudoparecido. Em vez disso, são apenas todos os argumentos para o script. E as aspas a seu redor não seriam supérfluas nesse caso? Caso contrário, se você fizer um sudo foo bar, ele tentará executar "foo bar"como um único comando, o que provavelmente não existe, devido ao medo irracional de espaços em sistemas do tipo UNIX.
Joey

7
@ Johnnes: "$@"(quando aspas duplas) funciona de forma diferente de "$*": se expande para uma palavra separada para cada variável posicional. Exemplo: Se $1 == "foo bar"e $2 == "baz", então "$@"é "foo bar" baz- uma palavra para cada parâmetro (diferente de "$*", que resulta em "foo bar baz"uma palavra). Consulte o manual da bashseção Parâmetros , subseção Parâmetros especiais . O resultado final do script de Peon é que ele executa seus argumentos exatamente como foram aprovados.
grawity

11
Ah ok. E de onde vem a sudoparte? O snippet acima não faz nada remotamente nessa direção, certo?
Joey

2
@ Johannes: No Unix, um real sudoaumentaria os privilégios de mortal para rootantes de executar o comando. No Cygwin, não existe isso, então o script falso do Peon (que você deve nomear sudo) apenas executa o comando diretamente sem alterar seus privilégios. (Isto significa que você pode precisar executar ./install.shcomo administrador.)
grawity

2
@rawity: runasdeve funcionar, não depende do UAC e solicita uma senha por si só. Fiquei confuso por que o script na resposta aparentemente não fez o que o nome implicava, que eu assumi ser o objetivo. Desculpem a minha estupidez ;-)
Joey

21

Encontrei a resposta na lista de e-mails do cygwin . Para executar commandcom privilégios elevados no Cygwin, preceda o comando da cygstart --action=runasseguinte maneira:

$ cygstart --action=runas command

Isso abrirá uma caixa de diálogo do Windows solicitando a senha de administrador e execute o comando se a senha apropriada for digitada.

Isso é facilmente script, contanto que ~/binesteja no seu caminho:

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

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

Testado no Windows 8 de 64 bits.


5
O problema com o cygstartmétodo é que ele funciona apenas para comandos / programas do Windows. Você não pode fazer sudo ls. O SUDO para CygWin é legal, mas ainda não possui um bom sudocomando.
Sopalajo de Arrierez

Obrigado, Sopalajode. Em que situação você precisou usar sudo lsno Cygwin?
dotancohen

3
Ah, não, @Dotancohen, foi apenas um exemplo. Você pode usar o sudoCygWin para executar qualquer comando do Windows ou CygWin. É bem útil para mim. Mas o método mais prático que encontrei é este wrapper de script para SUDO para CygWin que eu desenvolvi: superuser.com/questions/741345/… (ainda na versão beta, mas parece funcionar). Com ele, você pode encomendar confortavelmente coisas do tipo sudo net start vncserver.
Sopalajo de Arrierez

@SopalajodeArrierez: Isso é absolutamente fantástico! Obrigado pela postagem e pelo link.
dotancohen

curiosamente, isso retira /bine sai /usr/bindo PATH. Invoca com êxito o emacs: ShellExecute(NULL, "runas", "C:\cygwin64\bin\emacs-w32.exe", "(null)", "(null)", 1)mas, em seguida, o emacs não pode encontrar, lspor exemplo M-x dired, mesmo depois de restaurar interativamente o PATH usando (setenv ...). Existe um problema de caminhos confiáveis ​​aqui?
BaseZen 8/0318

5

Com base na resposta de dotancohen, estou usando um alias:

alias sudo="cygstart --action=runas"

Funciona como um encanto para programas externos (embora não sejam incorporados ao shell):

sudo chown User:Group <file>

3

Sudo (Elevate) para Windows ™

Eu trabalho muito na linha de comando no Windows ™.

No próprio Cygwin, acredito que você pode executar um comando raiz com o su -c /the/cmdpróprio sudo no sistema de arquivos do Windows ™, elevando as permissões do usuário na linha de comando. Se você é um administrador, isso funcionará muito bem para você. Caso contrário, use runas e obtenha o passe do administrador;).

Agora não me lembro de onde conseguimos esse código, mas aqui está ele. Espero que ajude.

BTW, o pacote que usamos para compilar isso foi 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
Este código é horrível. Está cheio de erros como não verificar o valor de retorno de realloc () antes de referenciar ou gravar sizeof (LPWSTR *) em vez de sizeof (* LPWSTR), em que LPWSTR parece ser um tipo de ponteiro e se deseja recuperar o tamanho de um caractere, não o tamanho do ponteiro. Além disso, não está totalmente claro por que, por exemplo, o caso 29 leva a ERROR_DDE_FAIL. Você pode concluir do código por quê? Não posso e acho que mais ninguém também pode. Por favor, não publique esse código no futuro.

4
@ Mattew: no futuro, ajude a comunidade postando uma versão limpa do snippet de código que você não gosta.
precisa saber é o seguinte

O código não deve estar no superusuário. Coloque-o em codereview.se e apenas vincule-o a partir daqui.
Ben Voigt

@ user185282: Bons pontos. Eu diminuí a votação.
Ingettableid

Caro tao: Você escreveu: "Não me lembro onde conseguimos esse código". Você escreveu esse código ou alguém o escreveu?
Ingettableid

2

Uma ligeira melhoria no script de sudo falso de Peon :

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

"$@"

Este script descarta silenciosamente todas as opções passadas para o sudo e executa o comando (sem realmente elevar os privilégios). Descartar as opções melhora um pouco a compatibilidade. Um script de wrapper mais completo deve analisar as opções da mesma maneira que o sudo.

Em vez de tentar substituir o sudo por um invólucro cygstart --action=runas "$@", basta usar esse invólucro falso e simples e executar o próprio script de instalação (ou o que você estiver tentando executar usando o sudo) com privilégios elevados.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.