Cách kiểm tra nếu chạy bằng root trong tập lệnh bash


273

Tôi đang viết một tập lệnh yêu cầu quyền cấp gốc và tôi muốn làm cho nó để nếu tập lệnh không chạy dưới quyền root, nó chỉ đơn giản lặp lại "Hãy chạy như root". và lối thoát hiểm.

Đây là một số mã giả cho những gì tôi đang tìm kiếm:

if (whoami != root)
  then echo "Please run as root"

  else (do stuff)
fi

exit

Làm thế nào tôi có thể tốt nhất (sạch sẽ và an toàn) hoàn thành việc này? Cảm ơn!

À, chỉ để làm rõ: phần (làm công cụ) sẽ liên quan đến việc chạy các lệnh mà bản thân chúng yêu cầu root. Vì vậy, chạy nó như một người dùng bình thường sẽ gặp lỗi. Điều này chỉ có nghĩa là để chạy sạch một tập lệnh yêu cầu các lệnh gốc, mà không sử dụng sudo bên trong tập lệnh, tôi chỉ tìm kiếm một số cú pháp cú pháp.


8
(1) làm cho nó không thể được thực thi bởi bất cứ điều gì khác sau đó root (2) cũng sắp xếp các quyền tiếp theo .. (3) id -utrả về 0cho root.
Wrikken

Câu trả lời:


403

Biến môi trường $ EUID giữ UID của người dùng hiện tại. UID của Root là 0. Sử dụng cái gì đó như thế này trong tập lệnh của bạn:

if [ "$EUID" -ne 0 ]
  then echo "Please run as root"
  exit
fi

Lưu ý: Nếu bạn nhận được 2: [: Illegal number:kiểm tra nếu bạn có #!/bin/shở đầu và thay đổi nó thành #!/bin/bash.


Có vẻ như các quyền tốt và có điều này là một lớp bảo mật kép
Kolob Canyon

25
Tôi nghĩ là tốt hơn để so sánh chuỗi với chuỗi, số với số. sử dụng dấu ngoặc kép, bạn có thể sử dụng> trực tiếp mà không có trích dẫn [[$ EUID> 0]]
Sergio Abreu

7
Tôi đã nhận được 2: [: Illegal number:cảnh báo cho đến khi thay đổi nó thành phiên bản của Sergio.
alexeydemin

1
@ thekiwi5000 Dấu chấm phẩy chỉ được yêu cầu nếu thentrên cùng một dòng với điều kiện ...
ptierno

1
@StephenAngelico Sudo nên hoạt động. Nếu bạn đang kiểm tra nó bằng cách thực hiện $ sudo echo $ EUID; đó là một thử nghiệm tồi và sẽ thất bại vì $ EUID được mở rộng trước khi lệnh được chuyển sang sudo. Hãy thử đặt echo $ EUID trong tập lệnh thử nghiệm và chạy nó với sudo.
dùng1169420

79

Trong tập lệnh bash, bạn có một số cách để kiểm tra xem người dùng đang chạy có phải là root hay không.

Để cảnh báo , đừng kiểm tra xem người dùng có root hay không bằng cách sử dụng roottên người dùng. Không có gì đảm bảo rằng người dùng có ID 0 được gọi root. Đó là một quy ước rất mạnh mẽ được theo dõi rộng rãi nhưng bất kỳ ai cũng có thể đổi tên siêu người dùng thành một tên khác.

Tôi nghĩ cách tốt nhất khi sử dụng bash là sử dụng $EUID, từ trang man:

EUID   Expands to the effective user ID of the current  user,  initialized
       at shell startup.  This variable is readonly.

Đây là một cách tốt hơn $UIDcó thể được thay đổi và không phản ánh người dùng thực sự đang chạy tập lệnh.

if (( $EUID != 0 )); then
    echo "Please run as root"
    exit
fi

Một cách tôi tiếp cận loại vấn đề đó là bằng cách tiêm sudovào các lệnh của tôi khi không chạy bằng root. Đây là một ví dụ:

SUDO=''
if (( $EUID != 0 )); then
    SUDO='sudo'
fi
$SUDO a_command

Bằng cách này, lệnh của tôi được chạy bởi root khi sử dụng superuser hoặc sudokhi được chạy bởi người dùng thông thường.

Nếu tập lệnh của bạn luôn được chạy bởi root, chỉ cần đặt quyền cho phù hợp ( 0500).


Nếu người đang cố chạy tập lệnh không có đặc quyền sudo, điều này sẽ khiến lỗi bị ném và lệnh sẽ không chạy? Chỉ muốn chắc chắn, tôi hiểu chính xác.
Caperneoignis

1
Tôi không chắc câu trả lời này hoàn toàn chính xác 100%. Trên RHEL7.2 bằng Bash 4.2.46 ... nếu tôi printf $EUIDcó hoặc không có sudo, tôi sẽ lấy lại UID của mình. Nếu tôi sử dụng, id -utôi nhận được UID của mình và khi tôi gọi nó bằng sudo, tôi nhận lại 0. Tôi đã làm gì sai sao?
0xSheepdog

4
@ 0xSheepdog, có thể trên bash cli, việc mở rộng biến $ EUID được giải quyết trước, sau đó sudo thay đổi người dùng. Do đó, bạn sẽ có hành vi đó, nhưng trong các kịch bản, mọi thứ vẫn sẽ hoạt động tốt.
Alexander Bird

@AlexanderBird Điểm tốt, cảm ơn bạn! Tôi đã không làm bất kỳ thử nghiệm thực tế, chỉ báo cáo kinh nghiệm của tôi.
0xSheepdog

3
Sử dụng "herestring" cho thử nghiệm của bạn để ngăn chặn sự mở rộng vỏ cục bộ của biến. So sánh sudo bash <<<'echo $EUID'với bash <<<'echo $EUID'. Thông tin thêm về di truyền giống như di truyền tại tldp.org/LDP/abs/html/x17837.html
Bruno Bronosky

74

Một vài câu trả lời đã được đưa ra, nhưng có vẻ như phương pháp tốt nhất là sử dụng là:

  • id -u
  • Nếu chạy bằng root, sẽ trả về id là 0.

Điều này dường như đáng tin cậy hơn các phương thức khác và dường như nó trả về id bằng 0 ngay cả khi tập lệnh được chạy qua sudo.


Tuyệt vời, đây là câu trả lời hay nhất
Dan Ortega

58
if [[ $(id -u) -ne 0 ]] ; then echo "Please run as root" ; exit 1 ; fi

hoặc là

if [[ `id -u` -ne 0 ]] ; then echo "Please run as root" ; exit 1 ; fi

:)


Bạn có thể cân nhắc việc tích hợp câu trả lời của Jeremy J Starcher với phần này, cuối cùng thì nó luôn giống như vậy ...
thực sự là

Tôi biết rằng từ thiết bị đầu cuối, khi tôi quên tiền tố một cái gì đó với sudotôi có thể chỉ cần gõ sudo !!và nó thực hiện công việc cho tôi, thay vì nhấn mũi tên LÊN, đi đến đầu dòng và thêm sudo bằng tay. Không chắc đó là thứ BASH hay thứ SUDO hay thứ khác, nhưng nó hoạt động hầu hết thời gian.
0xSheepdog

@ 0xSheepdog: Đó là một thứ Bash (và một tính năng của một số shell khác như csh, nơi IIRC nó bắt nguồn).
Tạm dừng cho đến khi có thông báo mới.

Tất cả trong tất cả, tôi sẽ loại bỏ toàn bộ phần backticky và viết lại dòng ok vào if [ "$(id -u)" -ne 0 ]; then echo 'Please run as root.' >&2; exit 1; fi. Chúc mừng.
LinuxSecurityFreak

29

Như @wrikken đã đề cập trong các bình luận của anh ấy, id -ulà một kiểm tra root tốt hơn nhiều.

Ngoài ra, với việc sử dụng đúng cách sudo, bạn có thể kiểm tra tập lệnh và xem nó có đang chạy bằng root hay không. Nếu không, hãy nhớ lại thông qua sudovà sau đó chạy với quyền root.

Tùy thuộc vào những gì tập lệnh thực hiện, một tùy chọn khác có thể là để thiết lập một sudomục nhập cho bất kỳ lệnh chuyên biệt nào mà tập lệnh có thể cần.


Có một cách duyên dáng để có một chương trình thu hồi chính nó? Có lẽ có một số biến bash với đường dẫn tuyệt đối đến chương trình?
Nathan

1
Tôi không ở gần dấu nhắc BASH ngay bây giờ để kiểm tra, nhưng $0có tên của tập lệnh đang chạy. Có một số ví dụ ở đây có thể giúp bạn.
Jeremy J Starcher

25

Có một kiểm tra đơn giản cho một người dùng đang root.

Các [[ stuff ]]cú pháp là cách tiêu chuẩn của chạy một kiểm tra trong bash.

error() {
  printf '\E[31m'; echo "$@"; printf '\E[0m'
}

if [[ $EUID -eq 0 ]]; then
    error "Do not run this as the root user"
    exit 1
fi

Điều này cũng giả sử rằng bạn muốn thoát bằng 1 nếu bạn thất bại. Các errorchức năng là một số flair rằng bộ sản lượng văn bản sang màu đỏ (không cần thiết, nhưng khá sang trọng nếu bạn hỏi tôi).


errorLệnh đó là gì? Hệ thống của tôi dường như không có nó. . .
ruakh

Ồ, đó chỉ là một điều nhỏ nhặt. Không quan trọng lắm, nhưng tôi sẽ đính kèm.
Slater Victoroff

4
Điều đó thật tuyệt! Nếu tôi có thể đề xuất một vài cải tiến: (1) chuyển dòng mới đến cuối; (2) ghi vào lỗi tiêu chuẩn thay vì đầu ra tiêu chuẩn; (3) chỉ đặt màu nếu lỗi tiêu chuẩn là một thiết bị đầu cuối (thay vì rủi ro ghi các ký tự thoát vào tệp nhật ký hoặc lesshoặc không có gì); và (4) đặt màu nền, vì vậy văn bản sẽ có thể đọc được bất kể màu nền của thiết bị đầu cuối của người dùng. Vì vậy, một cái gì đó như function error () { if [[ -t 2 ]] ; then echo $'\033[31;2;47m'"$@"$'\033[0m' ; else echo "$@" ; fi >&2 ; }. (Tinh chỉnh như mong muốn.)
ruakh

3
Không phải đó là "-ne" thay vì "-eq" sao?
Carlos Rendon

2
Mã của @CarlosRendon Slater là để ngăn thứ gì đó chạy dưới quyền root. (Điều này trái ngược với những gì OP yêu cầu, nhưng phương thức kiểm tra sẽ giống nhau.)
Joshua Taylor

11

Cách rất đơn giản chỉ cần đặt:

if [ "$(whoami)" == "root" ] ; then
    # you are root
else
    # you are not root
fi

Lợi ích của việc sử dụng này thay vì idlà bạn có thể kiểm tra xem một người dùng không phải root nào đó cũng đang chạy lệnh hay không; ví dụ.

if [ "$(whoami)" == "john" ] ; then
    # you are john
else
    # you are not john
fi

nếu bạn kiểm tra người dùng bằng chuỗi "root", bạn không cho phép chạy bất kỳ ai có tên "root"?
pcarvalho

Bạn đã quên ';' sau nếu
Triskeldeian

1
@peteroak ai khác sẽ được đặt tên gốc khác ngoài root?
ptierno

3
+1 để thực sự trả lời câu hỏi về whoamithay vì sử dụng id; các whoamilệnh cũng có thể được sử dụng để kiểm tra xem có khác người sử dụng hơn gốc, theo tên.
Jez

10

0- Đọc tài liệu GNU Linux chính thức, có nhiều cách để làm điều đó một cách chính xác.

1- đảm bảo bạn đặt chữ ký shell để tránh lỗi trong diễn giải:

 #!/bin/bash

2- đây là kịch bản của tôi

#!/bin/bash 

if [[ $EUID > 0 ]]; then # we can compare directly with this syntax.
  echo "Please run as root/sudo"
  exit 1
else
  #do your stuff
fi

10

Trong câu trả lời này, hãy nói rõ, tôi cho rằng người đọc có thể đọc bashcác kịch bản shell POSIX như thế nào dash.

Tôi tin rằng không có nhiều điều để giải thích ở đây vì các câu trả lời được bình chọn cao làm tốt công việc giải thích nhiều về nó.

Tuy nhiên, nếu có bất cứ điều gì để giải thích thêm, đừng ngần ngại bình luận, tôi sẽ cố gắng hết sức để lấp đầy các khoảng trống.


Tối ưu hóa bashgiải pháp toàn diện (không chỉ ) cho hiệu suất và độ tin cậy; tất cả các vỏ tương thích

Giải pháp mới:

# bool function to test if the user is root or not
is_user_root () { [ ${EUID:-$(id -u)} -eq 0 ]; }

Điểm chuẩn (lưu vào tệp is_user_root__benchmark)

###############################################################################
##                          is_user_root() benchmark                         ##
##                  Bash is fast while Dash is slow in this                  ##
##          Tested with Dash version 0.5.8 and Bash version 4.4.18           ##
##                     Copyright: 2020 Vlastimil Burian                      ##
##                      E-mail: info@vlastimilburian.cz                      ##
##                             License: GPL-3.0                              ##
##                               Revision: 1.0                               ##
###############################################################################

# intentionally, the file does not have executable bit, nor it has no shebang
# to use it, please call the file directly with your shell interpreter like:

# bash is_user_root__benchmark
# dash is_user_root__benchmark

# bool function to test if the user is root or not
is_user_root () { [ ${EUID:-$(id -u)} -eq 0 ]; }

# helper functions
print_time   () { date +"%T.%2N"; }
print_start  () { printf '%s' 'Start  : '; print_time; }
print_finish () { printf '%s' 'Finish : '; print_time; }

readonly iterations=10000

printf '%s\n' '______BENCHMARK_____'
print_start

i=1; while [ $i -lt $iterations ]; do
    is_user_root
    i=$((i + 1))
done

print_finish

Giải pháp ban đầu:

#!/bin/bash

is_user_root()
# function verified to work on Bash version 4.4.18
# both as root and with sudo; and as a normal user
{
    ! (( ${EUID:-0} || $(id -u) ))
}

if is_user_root; then
    echo 'You are the almighty root!'
else
    echo 'You are just an ordinary user.'
fi

^^ ^ Giải pháp nổi bật đã được chứng minh là không tăng tốc mọi thứ, nhưng nó đã có từ lâu, vì vậy tôi sẽ giữ nó ở đây miễn là tôi thấy cần thiết.


Giải trình

Vì việc đọc biến $EUIDtiêu chuẩn nhanh hơn nhiều lần bash, số ID người dùng hiệu quả, hơn là thực thi id -ulệnh để POSIX -ly tìm ID người dùng, giải pháp này kết hợp cả hai thành một chức năng được đóng gói độc đáo. Nếu và chỉ khi, $EUIDvì bất kỳ lý do nào không có sẵn, id -ulệnh sẽ được thực thi, đảm bảo chúng tôi nhận được giá trị trả về phù hợp bất kể trường hợp nào .


Tại sao tôi đăng giải pháp này sau nhiều năm OP đã hỏi

Chà, nếu tôi thấy chính xác, dường như có một đoạn mã bị thiếu ở trên.

Bạn thấy đấy, có rất nhiều biến số phải được tính đến, và một trong số đó là kết hợp hiệu suất và độ tin cậy .


Giải pháp POSIX di động + Ví dụ về việc sử dụng chức năng trên

#!/bin/sh

# bool function to test if the user is root or not (POSIX only)
is_user_root() { [ "$(id -u)" -eq 0 ]; }

if is_user_root; then
    echo 'You are the almighty root!'
    exit 0 # unnecessary, but here it serves the purpose to be explicit for the readers
else
    echo 'You are just an ordinary user.' >&2
    exit 1
fi

Phần kết luận

Nhiều như bạn có thể không thích, môi trường Unix / Linux đã đa dạng hóa rất nhiều. Có nghĩa là có những người thích bashrất nhiều, họ thậm chí không nghĩ đến tính di động ( vỏ POSIX ). Những người khác như tôi thích vỏ POSIX . Ngày nay nó là một vấn đề của sự lựa chọn và nhu cầu cá nhân.


6

Nếu tập lệnh thực sự yêu cầu quyền truy cập root thì quyền truy cập tập tin của nó sẽ phản ánh điều đó. Có một tập lệnh gốc được thực thi bởi người dùng không phải root sẽ là một cờ đỏ. Tôi khuyến khích bạn không kiểm soát truy cập bằng một ifkiểm tra.

chown root:root script.sh
chmod u=rwx,go=r script.sh

4
Nếu ai đó có quyền của họ để điều này hoạt động tốt, nhưng tôi cảm thấy việc lạm dụng 777bom khiến việc kiểm tra này có chút lỗi đối với loại người dùng sẽ mắc lỗi ngay từ đầu.
Slater Victoroff

7
Điều này giả sử người dùng đang chạy một tập lệnh thực thi. Nếu người dùng chỉ gọi bash /path/to/scriptnó vẫn có thể được chạy ngay cảo=r
ptierno

5

Một cách đơn giản để làm cho tập lệnh chỉ có thể chạy được bằng root là bắt đầu tập lệnh với dòng:

#!/bin/su root


1
Tôi tò mò tại sao câu trả lời này không được bình chọn cao hơn? Có vẻ như đơn giản và sạch sẽ nhất. Có những bất lợi ở đây?
Bassinator

@Bassinator Tôi tin rằng một số người nói rằng nó sẽ không chạy trên một số nix nhất định nhưng cho đến nay nó vẫn hoạt động hoàn hảo trên Linux của tôi. Thử nó! Có thể câu trả lời này đã đến muộn trong cuộc đua nhưng tôi đang cố gắng thêm kiến ​​thức đơn giản cho cộng đồng (thay vì đưa ra câu trả lời tương tự, giống như hầu hết trên chủ đề này: /) Hãy bình chọn nếu bạn may mắn đọc được nó và nó hoạt động trên máy của bạn
alexandre1985

@TamusJRoyce Nếu mục tiêu là kiểm tra xem bạn có đang chạy bằng root hay không buộc tập lệnh chỉ chạy bằng root, thì tại sao trong mỗi câu trả lời, sau khi kiểm tra xem có chạy bằng root không, họ có tạo tập lệnh exitkhông? Và những câu trả lời vẫn đang được nâng cao? Tôi đoán mọi người mặc nhiên không muốn tập lệnh được chạy dưới quyền root. Vì vậy, tôi đang theo cách nghĩ đó, với một câu trả lời đơn giản hơn. Nhưng vâng, bạn cũng có thể học hỏi từ những câu trả lời dài dòng hơn ở trên
alexandre1985

@ alexandre1985 Chính xác. Kịch bản: Nếu chạy bằng root, có thể bạn muốn một tập lệnh mặc định để cài đặt chương trình trên toàn cầu khi nó hỏi bạn muốn cài đặt nó như thế nào. Nếu không, mặc định được đặt để cài đặt cục bộ. Thay vì nhấn enter, người dùng có thể chọn cài đặt toàn cầu hoặc cục bộ. Nhưng nếu họ thích mặc định, họ có thể nhấn enter. Và họ sẽ không được nhắc với mật khẩu. Shebang của bạn sẽ không bao giờ "kiểm tra" nếu bạn là root (mỗi tiêu đề). Nhưng tôi vẫn nghĩ rằng câu trả lời này là hữu ích.
TamusJRoyce

@TamusJRoyce hoàn toàn có ý nghĩa bình luận của bạn. Quả thực là một mối quan tâm và giải pháp này không dành cho trường hợp sử dụng đó. Bạn đã mở quan điểm của tôi. Bạn đúng rồi. Cảm ơn
alexandre1985

4

thử đoạn mã sau:

if [ "$(id -u)" != "0" ]; then
    echo "Sorry, you are not root."
    exit 1
fi

HOẶC LÀ

if [ `id -u` != "0" ]; then
    echo "Sorry, you are not root."
    exit 1
fi


2

id -utốt hơn nhiều whoami, vì một số hệ thống như Android có thể không cung cấp từ gốc.

Thí dụ:

# whoami
whoami
whoami: unknown uid 0

0
#!/bin/bash

# GNU bash, version 4.3.46
# Determine if the user executing this script is the root user or not

# Display the UID
echo "Your UID is ${UID}"

if [ "${UID}" -eq 0 ]
then
    echo "You are root"
else
    echo "You are not root user"
fi

Lưu ý của biên tập viên: Nếu bạn không cần dấu ngoặc kép, hãy sử dụng dấu ngoặc đơn cho tính di động của mã.


3
Bạn đã không giải thích lý do tại sao bạn đã cung cấp một câu trả lời thay thế cho câu hỏi 5 tuổi đã có một số câu trả lời cho câu hỏi đó.
Styphon

0

Kiểm tra nếu bạn đã root và thoát nếu bạn không:

if ((EUID != 0)); then
    echo "Root or Sudo  Required for script ( $(basename $0) )"
    exit
fi

Hoặc trong ví dụ này, hãy thử tạo một thư mục ở vị trí gốc rồi thử sau khi quyền được nâng lên.

Kiểm tra nếu bạn là root và nếu không nâng cao nếu có thể:

# Fails to create these dirs (needs sudo)
mkdir /test-dir-$(basename $0)
rmdir /test-dir-$(basename $0)

if ((EUID != 0)); then
    echo "Granting root privileges for script ( $(basename $0) )"
    if [[ -t 1 ]]; then
        sudo "$0" "$@"
    else
        exec 1> output_file
        gksu "$0" "$@"
    fi
    exit
fi
echo "Root privileges granted..."
# Creates Dirs as it now has rights
mkdir /test-dir-$(basename $0)
rmdir /test-dir-$(basename $0)

-1

Kiểm tra root:

ROOT_UID=0   # Root has $UID 0.

if [ "$UID" -eq "$ROOT_UID" ]
then
  echo "You are root."
else
  echo "You are just an ordinary user."
fi

exit 0

Đã thử nghiệm và chạy trong root.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.