Truyền đối số cho shell do su cung cấp


8

man su nói:

You can use the -- argument to separate su options from the arguments
supplied to the shell.

man bash nói:

--        A  --  signals  the  end of options and disables further option
          processing.  Any arguments after the -- are treated as filenames
          and arguments.  An argument of - is equivalent to --.

Vậy thì, hãy xem:

[root ~] su - yuri -c 'echo "$*"' -- 1 2 3
2 3
[root ~] su - yuri -c 'echo "$*"' -- -- 1 2 3                                                       
2 3
[root ~] su - yuri -c 'echo "$*"' -- - 1 2 3                                                        
1 2 3
[root ~] su - yuri -c 'echo "$*"' - 1 2 3                                                           
1 2 3

Những gì tôi mong đợi (đầu ra của lệnh thứ hai khác nhau):

[root ~] su - yuri -c 'echo "$*"' -- 1 2 3
2 3
[root ~] su - yuri -c 'echo "$*"' -- -- 1 2 3                                                       
1 2 3
[root ~] su - yuri -c 'echo "$*"' -- - 1 2 3                                                        
1 2 3
[root ~] su - yuri -c 'echo "$*"' - 1 2 3                                                           
1 2 3

Có lẽ không có nhiều vấn đề. Nhưng chuyện gì đang xảy ra ở đó? Các biến thể thứ hai và thứ ba có vẻ giống như cách để đi, nhưng một trong số chúng không hoạt động. Cái thứ tư dường như không đáng tin cậy, -có thể được coi là sutùy chọn của.


Điều đó thật lạ. Tôi nhận được chính xác kết quả mà bạn mong đợi (và tôi cũng đồng ý với những kỳ vọng đó). Ý tôi là, trong trường hợp của lần gọi thứ hai, tôi nhận được "1 2 3" làm đầu ra. Tôi đang sử dụng bash 4.2.45trên cả tài khoản nguồn và đích.
Krzysztof Adamski

Câu trả lời:


9

Điều đang xảy ra là đối số đầu tiên bạn cung cấp cho shell là $0tham số, (thường đây sẽ là tên của shell). Nó không được bao gồm khi bạn làm echo $*$*mọi đối số ngoài $0.

Thí dụ:

# su - graeme -c 'echo "\$0 - $0"; echo "\$* - $*"' -- sh 1 2 3
$0 - sh
$* - 1 2 3

Cập nhật

Thực hiện lệnh sau:

strace -f su graeme -c 'echo $0; echo "$*"' -- -- 1 2 3

mang lại dòng strace:

[pid  9609] execve("/bin/bash", ["bash", "-c", "echo $0; echo \"$*\"", "1", "2", "3"], [/* 27 vars */] <unfinished ...>

Vì vậy, bằng cách nào đó, có vẻ như trong trường hợp sunày đang ngấu nghiến thêm --mà không chuyển nó sang bash, có thể là do lỗi (hoặc ít nhất là hành vi không có giấy tờ). Tuy nhiên, nó sẽ không ăn quá hai trong số các --đối số:

# su graeme -c 'echo $0; echo "$*"' -- -- -- 1 2 3
--
1 2 3

Điều đó tôi hiểu. Tôi làm : su - yuri -c 'echo "$*"' -- -- 1 2 3, vỏ được cho là -- 1 2 3, nhưng chỉ xuất ra 2 3. Nó thậm chí còn có ý nghĩa gì?
x-yuri

Và khi tôi làm bash -c 'echo $*' -- 1 2 3, nó xuất ra 1 2 3như mong đợi.
x-yuri

@ x-yuri, đã cập nhật. Đây dường như là một sulỗi.
Graeme

5

Trên thực tế câu trả lời của @ Graeme - và câu hỏi của bạn - chỉ tham khảo các tác dụng phụ về cách xử lý shell "$@positional $*parameters".Chúng được gán bởi shell cho các đối số của nó khi gọi và bất cứ lúc nào sau đó với settiện ích tích hợp. Chúng có thể được gọi bất cứ lúc nào với "$*"phân tách từng vị trí với ký tự đầu tiên "$IFS"hoặc "$@"trích dẫn từng vị trí và phân tách chúng với tất cả"$IFS."

man set

    NAME
       set  set or unset options and positional parameters

SYNOPSIS
       set [−abCefhmnuvx] [−o option] [argument...]

       set [+abCefhmnuvx] [+o option] [argument...]

       set −− [argument...]

       set o

       set +o

Nếu bạn đã có các giá trị mà bạn cho ăn vỏ, bạn không cần phải --ba lần. Các tham số Shell có setthể - luôn luôn, bất cứ lúc nào, không chỉ trong lệnh gọi (ngoại trừ $ 0 và -i):

su - mikeserv -c 'set -- "$*" ; echo "$*" ; 
    set -- 4 5 6 ; echo "$*"' -- -- 7 8 9

7 8 9
4 5 6

Và tất cả các trích dẫn vỏ đó có thể gây nhầm lẫn. Điều này đơn giản hóa mọi thứ một chút:

( set -- 4 5 6
    su - mikeserv 4<<-\CMD /dev/fd/4 "$@"
    echo $0 "$*"
    set -- "$*"
    echo "$*"
    set -- 7 8 9
    echo "$*"
CMD
)

/dev/fd/4 4 5 6
4 5 6
7 8 9

Các đối số của shell cha là set4, 5 và 6 và sau đó được chuyển đến lớp con được gọi suthông qua vị tríparameter "$@array".

Lưu ý cách tôi thực ( subshell )hiện lệnh trên - Tôi làm điều đó bởi vì tôi không muốn gây rối với môi trường shell hiện tại của mình - bởi vì tôi có thể vô tình thay đổi thứ gì đó mà tôi không muốn nếu tôi làm vớiset.

GIỚI THIỆU VỀ GIẢM GIÁ:

Trước hết, hệ thống Unix của bạn hoạt động với các tệp - quyền tệp, nội dung tệp, thuộc tính tệp. Bằng cách này hay cách khác, mọi đối tượng dữ liệu bạn sử dụng đều có thể (và, ít nhất là theo ý kiến ​​của tôi,) nên được xử lý như một tệp. Chuyển hướng trỏ đến một tập tin - đó là tất cả. A <<HERE-DOCUMENTsẽ mô tả một tập tin trong dòng sau đó chuyển hướng nó. Hoặc mở rộng vỏ được giải thích hoặc chúng không.

Người hỏi lưu ý trong các bình luận bên dưới rằng khi anh ta cố gắng sử dụng phương pháp này với tư cách là rootngười dùng, anh ta sẽ gặp lỗi về quyền. Khi tôi trả lời tôi đề nghị ông chownhoặc chgrpcác /dev/fd/${num}tập tin đặc biệt, nhưng điều này có lẽ không phải là phương pháp tốt nhất. Lý do anh gặp phải vấn đề này rootlà được cấp readquyền nhưng không phải là execute quyền. Bạn có thể dễ dàng xử lý điều này bằng cách tránh một execcuộc gọi. Thay vì gọi /dev/fd/${num}tệp trực tiếp trên dòng lệnh, hãy thực hiện:

su -c '. /dev/fd/'${num} ${num}<<SCRIPT 

Sử dụng hai heredocs có thể giúp thoát. Đây là những gì xảy ra trong mọi trường hợp:

KHÔNG CÀI ĐẶT <<HEREDOC

sh 3<<\CMD /dev/fd/3
    ( echo 'without set "$@" or \$@ in here-doc' ; echo
    set -- '1 "2" 3' 4 "5 6"
    su - mikeserv 4<<-UNQUOTED 5<<-\PREQUOTED /dev/fd/4
        echo UNQUOTED; echo $0 "$*"
        printf "%s\\t\\t%s\\t\\t%s\\t\\t%s\\n" $(printf "'%s' " "$@") \\
                $@ '$@' "$@" '"$@"' "'$@'" \$@ '\$@' "\$@" '"\$@"'
    . /dev/fd/5
    UNQUOTED
        echo PREQUOTED ; echo $0 "$*"
        printf "%s\t\t%s\t\t%s\t\t%s\n" $(printf "'%s' " "$@") \
                $@ '$@' "$@" '"$@"' \$@ '\$@' "\$@" '"\$@"'
    PREQUOTED
    )
CMD

ĐẦU RA

without set "$@" or \$@ in here-doc

UNQUOTED
/dev/fd/3 1 2 3 4 5 6
1 "2" 3         4               5 6             1
2               3               4               5
6               1 "2" 3 4 5 6           1 2 3 4 5 6             "1 "2" 3 4 5 6"
'1 2 3 4 5 6'           $@              "$@"
PREQUOTED
/dev/fd/5
''              $@              "$@"            $@
\$@             $@              "\$@"

SET "$@"TRÊN<<HEREDOC

sh 3<<\CMD /dev/fd/3
    ( echo 'set "$@" and \$@ in here-doc' ; echo
    set -- '1 "2" 3' 4 "5 6"
    su - mikeserv 4<<-UNQUOTED 5<<-\PREQUOTED /dev/fd/4
        set -- "$@" "\$@"
        echo UNQUOTED; echo $0 "$*"
        printf "%s\\t\\t%s\\t\\t%s\\t\\t%s\\n" $(printf "'%s' " "$@") \\
                $@ '$@' "$@" '"$@"' "'$@'" \$@ '\$@' "\$@" '"\$@"'
        . /dev/fd/5
    UNQUOTED
        set -- "$@" "\$@"
        echo PREQUOTED ; echo $0 "$*"
        printf "%s\t\t%s\t\t%s\t\t%s\n" $(printf "'%s' " "$@") \
                $@ '$@' "$@" '"$@"' \$@ '\$@' "\$@" '"\$@"'
    PREQUOTED
)
CMD

ĐẦU RA

set "$@" and \$@ in here-doc

UNQUOTED
/dev/fd/3 1 2 3 4 5 6
1 "2" 3         4               5 6             1
2               3               4               5
6               1 "2" 3 4 5 6           1 2 3 4 5 6             "1 "2" 3 4 5 6"
'1 2 3 4 5 6'           1 2 3 4 5 6             $@              1 2 3 4 5 6
"$@"
PREQUOTED
/dev/fd/5 1 2 3 4 5 6 $@
'1              2               3               4
5               6'              '$@'            1 2 3 4 5 6
$@              $@              1 2 3 4 5 6             $@
"$@"            $@              \$@             $@
"\$@"  

THIẾT LẬP "$@"VÀ THÊM<<HEREDOC

sh 3<<\CMD /dev/fd/3
    ( echo 'set "$@" and \$@ AND additional parameters in here-doc' ; echo
    set -- '1 "2" 3' 4 "5 6"
    su - mikeserv 4<<-UNQUOTED 5<<-\PREQUOTED /dev/fd/4
        set -- "$@" "\$@" '7 "8" 9' 10 "11 12"
        echo UNQUOTED; echo $0 "$*"
        printf "%s\\t\\t%s\\t\\t%s\\t\\t%s\\n" $(printf "'%s' " "$@") \\
                $@ '$@' "$@" '"$@"' "'$@'" \$@ '\$@' "\$@" '"\$@"'
        . /dev/fd/5
    UNQUOTED
        set -- "$@" "\$@" '13 "14" 15' 16 "17 18"
        echo PREQUOTED ; echo $0 "$*"
        printf "%s\t\t%s\t\t%s\t\t%s\n" $(printf "'%s' " "$@") \
                $@ '$@' "$@" '"$@"' \$@ '\$@' "\$@" '"\$@"'
    PREQUOTED
    )
CMD

ĐẦU RA

set "$@" and \$@ AND additional parameters in here-doc

UNQUOTED
/dev/fd/3 1 2 3 4 5 6
1 "2" 3         4               5 6             1
2               3               4               5
6               1 "2" 3 4 5 6           1 2 3 4 5 6             "1 "2" 3 4 5 6"
'1 2 3 4 5 6'           1 2 3 4 5 6             7 "8" 9         10
11 12           $@              1 2 3 4 5 6             7 "8" 9
10              11 12           "$@"
PREQUOTED
/dev/fd/5 1 2 3 4 5 6 7 "8" 9 10 11 12 $@ 13 "14" 15 16 17 18
'1              2               3               4
5               6'              '7              "8"
9'              '10'            '11             12'
'$@'            '13             "14"            15'
'16'            '17             18'             1 2 3 4 5 6
7 "8" 9         10              11 12           $@
13 "14" 15              16              17 18           $@
1 2 3 4 5 6             7 "8" 9         10              11 12
$@              13 "14" 15              16              17 18
"$@"            $@              \$@             $@
"\$@"  

Vấn đề là kịch bản đầu tiên của bạn mang lại cho tôi "8 9\n4 5 6\n". Tôi đang chạy debian 6, bash-4.1.5su.
x-yuri

@ x-yuri - và cái thứ hai, cái nào tránh được tất cả các trích dẫn lộn xộn?
mikeerv

Nếu chạy từ rootnó nói : -su: /dev/fd/4: Permission denied. Bạn có biết điều đó có nghĩa là gì không? Mặt khác, nó xuất ra như bạn nói, nhưng nó không giải quyết câu hỏi. Câu hỏi là về việc sử dụng ---.
x-yuri

@ x-yuri Tôi nghĩ điều đó có nghĩa là bạn sẽ cần chown /dev/fd/4trong khoảng thời gian bạn cần chgrp. Tôi không có nhiều thời gian để kiểm tra ngay bây giờ. Nhưng đó là một chút bên cạnh vấn đề, cũng như những điều khác mà bạn không cần phải vượt qua các đối số ở phần đuôi - chỉ cần làm việc trích dẫn của bạn. Thấy nó bây giờ?
mikeerv

Nếu chúng ta bỏ qua vấn đề sukhông thể làm việc với chuyển hướng stdin, việc truyền đối số vẫn tốt hơn sau đó đưa chúng vào lệnh. Bởi vì trong trường hợp sau bạn cần phải thoát khỏi chúng.
x-yuri
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.