ไม่มีคำสั่ง 'sudo' ใน Cygwin


41

เนื่องจากไม่มีคำสั่งsudoในCygwinสคริปต์ที่ฉันต้องการเรียกใช้ล้มเหลวด้วย

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

วิธีมาตรฐานในการแก้ไขปัญหานี้คืออะไร? การแก้ไขสคริปต์เพื่อลบsudo? กำลังรับsudoเครื่องมือที่คล้ายสำหรับ Windows?


@dotancohen ฉันหวังว่าฉันจะเลือกที่ถูกต้อง
Jason Sundram

ดูเหมือนเป็นทางออกที่ดีสำหรับฉัน! การสนับสนุน Cygwin นั้นดีขึ้นในช่วงห้าปีที่ผ่านมา!
dotancohen


@Benj ฉันสงสัยว่าทำไมคำถามนั้นไม่ได้ถูกย้ายที่นี่เช่นกัน
Jason Sundram

@ JasonSundram แน่นอน แจ้งให้เราทราบหากคำตอบถูกย้ายฉันจะอัปเดตลิงก์แล้ว
Benj

คำตอบ:


8

ฉันเขียนTOUACExt (ค่อนข้างง่าย) สำหรับSUDO สำหรับ CygWinซึ่งเป็นสคริปต์อัตโนมัติเชลล์รุ่นเบต้าที่เข้าใกล้พฤติกรรมของ Classical sudoสำหรับ Linux:

  • เปิดและปิดอัตโนมัติ sudoserver.py เมื่อต้องการ
  • ขอให้ยกระดับUAC

การติดตั้งจำเป็นต้องคัดลอกสี่.shสคริปต์ไปยังไดเรกทอรีพา ธ บางส่วนสร้างนามแฝงและเพียงไม่กี่ขั้นตอนรายละเอียดเพิ่มเติมในเธรด

ผลลัพธ์ : คุณพิมพ์เพียงครั้งเดียวsudo YourCommandและรับผลลัพธ์โดยไม่ต้องกังวลเกี่ยวกับกระบวนการที่เหลือ


35

วิธีหนึ่งคือการสร้างคำสั่ง "sudo" ปลอมด้วยเนื้อหาต่อไปนี้:

#!/usr/bin/bash

"$@"

สิ่งนี้จะทำให้การinstall.shดำเนินการต่อเนื่องจากพบ sudo

สิ่งนี้ไม่ยกระดับสิทธิ์ใช้งานเหมือนที่ sudo จริงทำ หากคุณต้องการสิทธิ์ยกระดับเริ่มต้นเชลล์ cygwin ด้วยจากบัญชีที่มีสิทธิ์ระดับผู้ดูแลระบบ (XP) หรือคลิก r บน cygwin.bat และ"run as administrator" (Vista, Win7)


5
เพิ่งออกมาจากความอยากรู้อยากเห็นจากคนที่ไม่พูดคล่องbash: ทำไมงานนี้? manpage ไม่ได้พูดอะไรเกี่ยวกับ$@การทำอะไรที่sudoเหมือน มันเป็นเพียงข้อโต้แย้งทั้งหมดของสคริปต์ และคำพูดรอบ ๆ มันจะไม่ฟุ่มเฟือยในกรณีนี้หรือไม่? มิฉะนั้นถ้าคุณทำsudo foo barแล้วมันจะพยายามดำเนินการ"foo bar"เป็นคำสั่งเดียวซึ่งอาจไม่มีอยู่เนื่องจากความกลัวที่ไม่ลงตัวของช่องว่างบนระบบที่คล้ายกับ UNIX
Joey

7
@Johannes: "$@"(เมื่ออ้างสองครั้ง) ทำงานแตกต่างจาก"$*": มันขยายเป็นคำที่แยกต่างหากสำหรับตัวแปรตำแหน่งทุก ตัวอย่าง:ถ้า$1 == "foo bar"และ$2 == "baz"จากนั้น"$@"คือ"foo bar" baz- หนึ่งคำสำหรับแต่ละพารามิเตอร์ (ไม่เหมือน"$*"กันซึ่งส่งผล"foo bar baz"ให้เป็นหนึ่งคำ) ดูคู่มือการใช้งานbashส่วนพารามิเตอร์ , หมวดพารามิเตอร์พิเศษ ผลลัพธ์สุดท้ายของสคริปต์ของ Peon คือมันประมวลผลการขัดแย้งของมันอย่างที่ผ่านมา
grawity

1
อาโอเค. แล้วsudoส่วนไหนจะเข้ามา ตัวอย่างด้านบนไม่ได้ทำอะไรจากระยะไกลในทิศทางนั้นใช่ไหม
Joey

2
@Johannes: ใน Unix ของจริงsudoจะยกระดับสิทธิพิเศษจากมนุษย์ให้ถึงrootก่อนที่จะใช้คำสั่ง ใน Cygwin ไม่มีสิ่งนั้นดังนั้นสคริปต์ปลอมของ Peon (ซึ่งคุณควรจะตั้งชื่อsudo) เพียงแค่เรียกใช้คำสั่งโดยตรงโดยไม่เปลี่ยนสิทธิ์ของมัน (ซึ่งหมายความว่าคุณอาจต้องเรียกใช้./install.shในฐานะผู้ดูแลระบบ)
grawity

2
@grawity: runasควรใช้งานไม่ต้องพึ่งพา UAC และแจ้งรหัสผ่านด้วยตัวเอง ฉันเพิ่งสับสนว่าทำไมสคริปต์ในคำตอบดูเหมือนไม่ได้ทำในสิ่งที่ชื่อโดยนัยซึ่งฉันถือว่าเป็นเป้าหมาย ขออภัยในความโง่เขลาของฉัน ;-)
Joey

21

ผมพบคำตอบในรายชื่อที่ส่งของ cygwin ในการรันcommandด้วยสิทธิ์ยกระดับใน Cygwin ให้ทำหน้าคำสั่งด้วยcygstart --action=runasวิธีนี้:

$ cygstart --action=runas command

นี่จะเป็นการเปิดกล่องโต้ตอบ Windows เพื่อขอรหัสผ่านผู้ดูแลระบบและเรียกใช้คำสั่งหากป้อนรหัสผ่านที่เหมาะสม

นี่เป็นสคริปต์อย่างง่ายดายตราบใดที่~/binอยู่ในเส้นทางของคุณ:

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

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

ทดสอบกับ Windows 8 64 บิต


5
ปัญหาของcygstartวิธีนี้คือใช้ได้กับคำสั่ง / โปรแกรมของ Windows เท่านั้น sudo lsคุณไม่สามารถทำ SUDO สำหรับ CygWin นั้นเรียบร้อย แต่ก็ยังขาดsudoคำสั่งที่ดีอยู่
Sopalajo de Arrierez

ขอบคุณ Sopalajode คุณต้องการใช้สถานการณ์sudo lsใน Cygwin ในสถานการณ์ใดบ้าง
dotancohen

3
โอ้ไม่ @Dotancohen มันเป็นเพียงตัวอย่าง คุณสามารถใช้sudoสำหรับ CygWin เพื่อรันคำสั่ง Windows หรือ CygWin มันมีประโยชน์มากสำหรับฉัน แต่วิธีการที่ใช้ประโยชน์ได้มากกว่าที่ฉันพบคือชุดหุ้มสคริปต์สำหรับ SUDO สำหรับ CygWin ที่ฉันพัฒนาขึ้น: superuser.com/questions/741345/… (ยังอยู่ในเบต้า แต่ดูเหมือนว่าจะใช้งานได้) sudo net start vncserverด้วยคุณสะดวกสบายสามารถสั่งซื้อสิ่งที่ต้องการ
Sopalajo de Arrierez

@SopalajodeArrierez: นั่นยอดเยี่ยมจริงๆ! ขอบคุณสำหรับการโพสต์และลิงค์
dotancohen

อยากรู้อยากเห็นแถบนี้ออกมา/binและจาก/usr/bin PATHมันไม่ประสบความสำเร็จวิงวอน emacs: ShellExecute(NULL, "runas", "C:\cygwin64\bin\emacs-w32.exe", "(null)", "(null)", 1)แต่แล้ว emacs ไม่สามารถหาlsสำหรับเช่นแม้หลังจากการโต้ตอบการฟื้นฟูเส้นทางโดยใช้M-x dired (setenv ...)มีปัญหาเส้นทางที่เชื่อถือได้ที่นี่หรือไม่?
BaseZen

5

การสร้างคำตอบของ dotancohenฉันใช้นามแฝง:

alias sudo="cygstart --action=runas"

ใช้งานได้อย่างมีเสน่ห์สำหรับโปรแกรมภายนอก (ไม่ใช่ shell built-ins)

sudo chown User:Group <file>

3

Sudo (ยกระดับ) สำหรับ Windows ™

ฉันทำงานเป็นจำนวนมากบนบรรทัดคำสั่งใน Windows ™

ใน Cygwin ฉันเชื่อว่าคุณสามารถรันคำสั่งรูทด้วยsu -c /the/cmdสำหรับ sudo เองภายในระบบไฟล์ของ Windows ™เพื่อยกระดับสิทธิ์ของผู้ใช้จากบรรทัดคำสั่งหากคุณเป็นผู้ดูแลระบบสิ่งนี้จะใช้ได้ผลดีสำหรับคุณ มิฉะนั้นให้ใช้ Runas และรับรหัสผ่านของผู้ดูแลระบบ;)

ตอนนี้ฉันจำไม่ได้ว่าเราได้รับรหัสนี้จากที่ใด ฉันหวังว่ามันจะช่วย

BTW, 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
รหัสนี้แย่มาก มันเต็มไปด้วยข้อผิดพลาดที่ไม่ได้ตรวจสอบค่าส่งคืนของ realloc () ก่อนที่จะยกเลิกการประชุมหรือเขียน sizeof (LPWSTR *) แทน sizeof (* LPWSTR) ที่ LPWSTR ดูเหมือนจะเป็นประเภทตัวชี้และต้องการดึงขนาดหนึ่งอักขระ ขนาดของตัวชี้ นอกจากนี้ยังไม่มีความชัดเจนว่าทำไมเช่นกรณีที่ 29 นำไปสู่ ​​ERROR_DDE_FAIL คุณสามารถสรุปได้จากรหัสทำไม? ฉันทำไม่ได้และฉันก็เดาว่าไม่มีใครอีกเช่นกัน กรุณาอย่าโพสต์รหัสดังกล่าวในอนาคต

4
@Mattew: โปรดช่วยชุมชนในอนาคตโดยโพสต์ข้อมูลโค้ดที่คุณไม่ชอบ
Erik Allik

รหัสไม่ควรอยู่ใน superuser วางไว้บน codereview.se และเพียงลิงก์จากที่นี่
Ben Voigt

@ user185282: คะแนนดี ฉันลงคะแนนคำตอบ
ลืม

เรียนเต่า: คุณเขียนว่า "ฉันจำไม่ได้ว่าเราได้รหัสนี้มาจากไหน" คุณเขียนรหัสนี้หรือคนอื่นเขียนหรือไม่
ลืม

2

การปรับปรุงเล็กน้อยในสคริปต์sudo ปลอมของ Peon :

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

"$@"

สคริปต์นี้จะลดตัวเลือกใด ๆ ที่ส่งผ่านไปยัง sudo และดำเนินการคำสั่ง (โดยไม่ยกระดับสิทธิ์) การลดตัวเลือกปรับปรุงความเข้ากันได้บ้าง สคริปต์ตัวตัดคำที่สมบูรณ์ยิ่งขึ้นควรแยกวิเคราะห์ตัวเลือกตามที่ sudo ทำ

แทนที่จะพยายามแทนที่ sudo ด้วย wrapper ที่cygstart --action=runas "$@"ใช้เพียงแค่ใช้sudo wrapper ปลอมนี้แล้วเรียกใช้สคริปต์การติดตั้งของคุณเอง (หรือสิ่งที่คุณพยายามเรียกใช้ที่ใช้ sudo) ด้วยสิทธิ์ระดับสูง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.