Trường hợp zsh và mksh không tương thích với bash?


11

Ở mức độ nào thì các shell tương thích POSIX khác có thể hoạt động như sự thay thế hợp lý cho bash? Chúng không cần phải là sự thay thế "thả vào" thực sự, nhưng đủ gần để làm việc với hầu hết các tập lệnh và hỗ trợ phần còn lại với một số sửa đổi.

  1. Tôi muốn có các tập lệnh bash rõ ràng - initscripts, DHCP client script, v.v. - hoạt động với sửa đổi tối thiểu

  2. Tôi muốn bộ sưu tập các kịch bản shell chuyên dụng hơn của mình không cần sửa đổi quá nhiều

  3. Tôi muốn có các tính năng như thao tác chuỗi và khớp mẫu regex tích hợp

Các ứng cử viên nghiêm trọng duy nhất tôi biết là zsh và mksh. Vì vậy, đối với những người ở đây, những người tốt với một hoặc cả hai:

  1. Bash có những tính năng nào mà zsh và mksh tương ứng không có?

  2. Những tính năng nào mà shell chia sẻ với bash, nhưng sử dụng cú pháp không tương thích cho?


3
So sánh các Shells Command: ( en.wikipedia.org/wiki/Comparison_of_command_shells ) nâng cao Hướng dẫn Bash Scripting: ( tldp.org/LDP/abs/html ) Zsh Manual: ( zsh.sourceforge.net/Guide/zshguide.html ) MirBSD Hướng dẫn sử dụng Shell: ( mirbsd.org/htman/i386/man1/mksh.htm ). Tôi xin lỗi, nhưng câu hỏi này quá phức tạp. Có lẽ bạn nên hỏi làm thế nào để vá bash để khắc phục lỗ hổng trong phân phối Linux cụ thể của bạn?
Tyler Maginnis

3
Không có lớp vỏ nào có thể hoạt động như một sự thay thế bash, mksh và zsh có thể hoạt động như /bin/shvới các mức độ chính xác khác nhau, nhưng không bash.
llua

1
Toàn bộ điều vỏ sò dường như không liên quan gì đến câu hỏi cốt lõi và chỉ khiến mọi người mất tập trung, vì vậy tôi đã gỡ bỏ nó
Michael Mrozek

3
Toàn bộ câu hỏi là quá rộng. Có lẽ bạn nên loại bỏ nó.
Tyler Maginnis

1
Mối quan tâm duy nhất tôi thực sự có là BASH được Quỹ Phần mềm Tự do (FSF) duy trì tốt. Các liên hệ của tôi ở đó cho tôi biết rằng sự tiết lộ về "lỗ hổng cơ bản" trong BASH sẽ chỉ dẫn đến việc triển khai mạnh mẽ hơn, an toàn hơn. Có rất nhiều vỏ thay thế mà thậm chí bắt đầu đề xuất một loại cho yêu cầu của bạn, tôi sẽ yêu cầu một sự hiểu biết vững chắc về trường hợp sử dụng của bạn. Sau đó, về phía O / S ... Rất nhiều điều gắn liền với Bash mà cuối cùng bạn có thể viết lại toàn bộ các cuộc gọi O / S của mình thành BASH. Giải pháp tốt nhất tôi có thể thấy là chọn phân phối có vỏ thay thế được bảo trì.
Tyler Maginnis

Câu trả lời:


19

Tôi sẽ gắn bó với các tính năng kịch bản. Các tính năng tương tác phong phú (phiên bản dòng lệnh, hoàn thành, lời nhắc, v.v.) có xu hướng rất khác nhau, đạt được hiệu ứng tương tự theo những cách hoàn toàn không tương thích. Những tính năng nào trong zsh và thiếu từ bash, hoặc ngược lại? đưa ra một vài gợi ý về việc sử dụng tương tác.

Thứ gần nhất với bash sẽ là ATT ksh93 hoặc mksh (vỏ Korn và một bản sao). Zsh cũng có một tập hợp các tính năng nhưng bạn sẽ cần chạy nó ở chế độ mô phỏng ksh, không phải ở chế độ gốc zsh.

Tôi sẽ không liệt kê các tính năng POSIX (có sẵn trong bất kỳ trình shbao hiện đại nào ), cũng không phải là các tính năng tương đối khó hiểu, cũng như các tính năng được đề cập ở trên để sử dụng tương tác. Các quan sát có giá trị như bash 4.2, ksh 93u và mksh 40.9.20120630 như được tìm thấy trên Debian wheezy.

Cú pháp Shell

Trích dẫn

$'…'(chuỗi ký tự với nội suy dấu gạch chéo ngược) có sẵn trong ksh93 và mksh. `$" '"(Chuỗi dịch) là đặc trưng bash.

Cấu trúc có điều kiện

Mksh và ksh93 phải ;&thông qua một casetuyên bố, nhưng không ;;&kiểm tra các trường hợp tiếp theo. Mksh đã ;|cho điều đó, và mksh gần đây cho phép ;;&tương thích.

((…))biểu thức số học và [[ … ]]kiểm tra là các tính năng ksh. Một số toán tử có điều kiện là khác nhau, hãy xem các biểu thức điều kiện có điều kiện khác bên dưới.

Đồng xử lý

Cả Ksh và bash đều có bộ đồng xử lý nhưng chúng hoạt động khác nhau.

Chức năng

Mksh và ksh93 hỗ trợ function name {…}cú pháp cho các định nghĩa hàm ngoài tiêu chuẩn name () {…}, nhưng sử dụng functiontrong ksh sẽ thay đổi các quy tắc phạm vi, vì vậy hãy kiên name () …trì để duy trì khả năng tương thích. Các quy tắc cho các ký tự được phép trong tên hàm khác nhau; dính vào chữ và số _.

Niềng răng mở rộng

Ksh93 và mksh hỗ trợ mở rộng nẹp {foo,bar}. Ksh93 hỗ trợ phạm vi số {1..42}nhưng mksh thì không.

Mở rộng tham số

Ksh93 và hỗ trợ chuỗi khai thác mksh với ${VAR:offset}${VAR:offset:length}, nhưng không phải trường hợp gấp như ${VAR^}, ${VAR,}vv Bạn có thể làm chuyển đổi trường hợp typeset -ltypeset -utrong cả bash và ksh.

Họ hỗ trợ thay thế bằng ${VAR/PATTERN/STRING}hoặc ${VAR/PATTERN//STRING}. Các quy tắc trích dẫn cho STRING hơi khác nhau, do đó, tránh dấu gạch chéo ngược (và có thể các ký tự khác) trong STRING (xây dựng một biến và sử dụng ${VAR/PATTERN/$REPLACEMENT}thay thế nếu thay thế có chứa các ký tự trích dẫn).

Mảng mở rộng ( ${ARRAY[KEY]}, "${ARRAY[@]}", ${#ARRAY[@]}, ${!ARRAY[@]}) làm việc trong bash như trong ksh.

${!VAR}mở rộng đến ${OTHERVAR}khi giá trị của VAROTHERVAR(gián tiếp biến tài liệu tham khảo) là bash cụ thể (ksh làm điều gì đó khác nhau với ${!VAR}). Để có được mở rộng gấp đôi này trong ksh, bạn cần sử dụng tham chiếu tên thay thế ( typeset -n VAR=OTHERVAR; echo "$VAR"). ${!PREFIX*}hoạt động như nhau

Quá trình thay thế

Quá trình thay thế <(…)>(…)được hỗ trợ trong ksh93 nhưng không phải trong mksh.

Mẫu ký tự đại diện

Các mẫu toàn cầu mở rộng ksh cần shopt -s extglobđược kích hoạt trong bash luôn có sẵn trong ksh93 và mksh.

Mksh không hỗ trợ các lớp nhân vật như [[:alpha:]].

Chuyển hướng IO

Bash và ksh93 định nghĩa các tệp giả và , nhưng mksh thì không./dev/tcp/HOST/PORT/dev/udp/HOST/PORT

Mở rộng các ký tự đại diện để chuyển hướng trong các tập lệnh (như var="*.txt"; echo hello >$abằng văn bản a.txtnếu tên tệp đó là đối sánh duy nhất cho mẫu) là một tính năng dành riêng cho bash (các shell khác không bao giờ thực hiện trong các tập lệnh).

<<< chuỗi ở đây hoạt động trong ksh như trong bash.

Phím tắt >&để chuyển hướng lỗi cú pháp cũng được hỗ trợ bởi mksh nhưng không phải bởi ksh93.

Biểu thức điều kiện

[[ … ]] cú pháp ngoặc kép

Cú pháp ngoặc kép từ ksh được hỗ trợ bởi cả ATT ksh93 và mksh như trong bash.

Toán tử tập tin

Ksh93, mksh và hỗ trợ bash các phần mở rộng cùng với POSIX, bao gồm -anhư một từ đồng nghĩa lỗi thời của -e, -k(dính), -G(thuộc sở hữu của egid), -O(chủ sở hữu bởi euid), -ef(cùng một tập tin), -nt(mới hơn), -ot(lớn hơn).

-N FILE (sửa đổi từ lần đọc trước) không được mksh hỗ trợ.

Mksh không có toán tử khớp regrec =~. Ksh93 có toán tử này và nó thực hiện tương tự như trong bash, nhưng sau đó không có tương đương BASH_REMATCHđể truy xuất các nhóm khớp.

Toán tử chuỗi

Ksh93 và mksh hỗ trợ các toán tử so sánh chuỗi giống nhau <>như bash cũng như ==từ đồng nghĩa của =. Mksh không sử dụng cài đặt ngôn ngữ để xác định thứ tự từ điển, nó so sánh các chuỗi như chuỗi byte.

Các nhà khai thác khác

-v VARđể kiểm tra nếu một biến được định nghĩa là đặc trưng bash. Trong bất kỳ vỏ POSIX, bạn có thể sử dụng [ -z "${VAR+1}" ].

Nội địa

alias

Tập hợp các ký tự được phép trong các tên bí danh không giống nhau trong tất cả các shell. Tôi nghĩ nó giống như cho các chức năng (xem ở trên).

builtin

Ksh93 có một lệnh dựng sẵn builtin, nhưng nó không thực thi tên dưới dạng lệnh tích hợp. Sử dụng commandđể bỏ qua các bí danh và chức năng; cái này sẽ gọi hàm dựng sẵn nếu có, nếu không thì lệnh bên ngoài (bạn có thể tránh điều này với PATH= command error_out_if_this_is_not_a_builtin).

caller

Đây là bash cụ thể. Bạn có thể nhận được một hiệu ứng tương tự với .sh.fun, .sh.file.sh.linenotrong ksh93. Trong mksh cuối cùng cũng có LINENO.

declare, local,typeset

declarelà một tên riêng của bash cho ksh's typeset. Sử dụng typeset: nó cũng hoạt động trong bash.

Mksh định nghĩa localnhư một bí danh cho typeset. Trong ksh93, bạn cần sử dụng typeset(hoặc xác định bí danh).

Mksh không có mảng kết hợp (chúng được dự kiến ​​là phiên bản chưa được phát hành).

Tôi không nghĩ rằng có một tương đương chính xác của bash's typeset -t(hàm theo dõi) trong ksh.

cd

Ksh93 không có -e.

echo

Ksh93 và mksh xử lý các tùy chọn -e-nnhư trong bash. Mksh cũng hiểu -E, ksh93 không coi đó là một lựa chọn. Mở rộng dấu gạch chéo ngược được tắt theo mặc định trong ksh93, theo mặc định trong mksh.

enable

Ksh không cung cấp cách để vô hiệu hóa các lệnh dựng sẵn. Để tránh tích hợp sẵn, hãy tìm đường dẫn của lệnh bên ngoài và gọi nó một cách rõ ràng.

exec

Ksh93 có -anhưng không -l. Mksh không có.

export

Cả ksh93 và mksh đều không có export -n. Sử dụng typeset +x foothay thế, nó hoạt động trong bash và ksh.

Ksh không xuất các chức năng thông qua môi trường.

let

let là giống nhau trong bash và ksh.

mapfile, readarray

Đây là một tính năng cụ thể bash. Bạn có thể sử dụng while readcác vòng lặp hoặc thay thế lệnh để đọc một tệp và chia nó thành một mảng các dòng. Hãy chăm sóc IFSvà Globing. Đây là tương đương với mapfile -t lines </path/to/file:

IFS=$'\n'; set -f
lines=($(</path/to/file))
unset IFS; set +f

printf

printfrất giống nhau Tôi nghĩ rằng ksh93 hỗ trợ tất cả các chỉ thị định dạng của bash. mksh không hỗ trợ %qhoặc %(DATE_FORMAT)T; trên một số cài đặt, printfkhông phải là một mksh dựng sẵn và thay vào đó gọi lệnh bên ngoài.

printf -v VAR là đặc trưng của bash, ksh luôn in ra đầu ra tiêu chuẩn.

read

Một số tùy chọn là dành riêng cho bash, bao gồm tất cả các tùy chọn về đường dẫn. Các tùy chọn -r, -d, -n, -N, -t, -ulà giống hệt nhau trong bash, ksh93 và mksh.

readonly

Bạn có thể khai báo một biến là chỉ đọc trong Ksh93 và mksh với cùng một cú pháp. Nếu biến là một mảng, bạn cần gán cho nó trước, sau đó làm cho nó chỉ đọc với readonly VAR. Các chức năng không thể được thực hiện chỉ đọc trong ksh.

set, shopt

Tất cả các tùy chọn đến setset -olà các tính năng POSIX hoặc ksh.

shoptlà bash cụ thể. Nhiều lựa chọn liên quan đến việc sử dụng tương tác nào. Để biết các hiệu ứng trên toàn cầu và các tính năng khác được kích hoạt bởi một số tùy chọn, hãy xem phần Tùy chọn liên kết bên dưới.

source

Biến thể này .tồn tại trong ksh là tốt. Trong bash và mksh, sourcetìm kiếm thư mục hiện tại sau PATH, nhưng trong ksh93, nó tương đương chính xác ..

trap

Các DEBUGgiả tín hiệu không được thực hiện trong mksh. Trong ksh93, nó tồn tại với một cách khác để báo cáo thông tin, xem hướng dẫn để biết chi tiết.

type

Trong ksh, typelà một bí danh cho whence -v. Trong mksh, type -pkhông in đường dẫn đến tệp thực thi, mà là một thông điệp có thể đọc được; bạn cần sử dụng whence -p COMMANDthay thế

Tùy chọn

shopt -s dotglob - đừng bỏ qua các tập tin dấu chấm trong globalbing

Để mô phỏng dotglobtùy chọn trong ksh93, bạn có thể đặt FIGNORE='@(.|..)'. Tôi không nghĩ có bất cứ điều gì như thế này trong mksh.

shopt -s extglob - ksh mô hình toàn cầu mở rộng

Các extglobtùy chọn có hiệu quả luôn luôn trong ksh.

shopt -s failglob - lỗi nếu mẫu hình cầu không khớp

Tôi không nghĩ rằng điều này tồn tại trong cả mksh hoặc ksh93. Nó thực hiện trong zsh (hành vi mặc định trừ khi null_globhoặc csh_null_globđược đặt).

shopt -s globstar**/Globing đệ quy

Ksh93 có tính năng đệ quy đệ quy với **/, được bật với set -G. Mksh không có tính năng đệ quy đệ quy.

shopt -s lastpipe - chạy lệnh cuối cùng của đường ống trong shell cha

Ksh93 luôn chạy lệnh cuối cùng của một đường ống trong shell cha, trong bash yêu cầu lastpipetùy chọn được đặt. Mksh luôn chạy lệnh cuối cùng của một đường ống trong một lớp con.

shopt -s nocaseglob, shopt -s nocasematch- mẫu không phân biệt chữ hoa chữ thường

Mksh không có kết hợp mẫu không phân biệt chữ hoa chữ thường. Ksh93 hỗ trợ nó trên cơ sở từng mẫu: tiền tố mẫu với ~(i).

shopt -s nullglob - mở rộng các mẫu không khớp với tệp vào danh sách trống

Mksh không có cái này. Ksh93 hỗ trợ nó trên cơ sở từng mẫu: tiền tố mẫu với ~(N).

Biến

Rõ ràng hầu hết các BASH_xxxbiến không tồn tại trong ksh. $BASHPIDcó thể được mô phỏng với chi phí cao nhưng di động sh -c 'echo $PPID'và gần đây đã được thêm vào mksh. BASH_LINE.sh.linenotrong ksh93 và LINENOtrong mksh. BASH_SUBSHELL.sh.subshellở ksh93.

Mksh và ksh93 đều nguồn tệp được cung cấp ENVkhi chúng khởi động.

EUIDUIDkhông tồn tại trong ksh93. Mksh gọi họ USER_IDKSH_UID; nó không có GROUPS.

FUNCNAMEFUNCNESTkhông tồn tại trong ksh. Ksh93 có .sh.fun.sh.level. Các hàm được khai báo với function foo { …; }(không có dấu ngoặc đơn!) Có tên riêng của chúng trong $0.

GLOBIGNOREtồn tại trong ksh93 nhưng với một tên và cú pháp khác: nó được gọi FIGNOREvà đó là một mẫu duy nhất, không phải là danh sách được phân tách bằng dấu hai chấm. Sử dụng một @(…|…)mô hình. Ksh's FIGNOREsubs bash's, với một cú pháp hoàn toàn khác.

Ksh93 và mksh không có gì giống như HOSTTYPE, MACHTYPEOSTYPE. Cũng không SHELLOPTShay TIMEFORMAT.

Mksh có PIPESTATUS, nhưng ksh93 thì không.

Mksh và ksh93 có RANDOM.


nếu bạn không muốn sao chép chính xác nhãn hiệu (chưa đăng ký), thì mksh Hồi chính xác ở đầu câu ( cũng xem phần "dd". "so với" "". Tại đây ), vui lòng viết vào The MirBSD Thay vào đó là Korn Shell. Đó là luôn luôn sai để tận dụng bất kỳ thư “mksh”. Cảm ơn.
mirabilos

Làm thế nào có thể $BASHPIDđược mô phỏng với sh -c 'echo $PPID'? Tôi đã thử (sh -c 'echo $PPID')ở Bash nhưng nó mang lại cho tôi cùng một PID $$.
Franklin Yu

Tôi nghĩ rằng câu hỏi phù hợp hơn ở đây . Tôi đã sao chép câu hỏi ở đó.
Franklin Yu

4

Câu hỏi này khá rộng.

Cả mkshzsh đều là các shell hỗ trợ rất nhiều phần mở rộng bash -specific của GNU , nhưng luôn có một số phần không được hiểu.

zsh hỗ trợ nhiều thứ hơn, nhưng chỉ trong chế độ zsh gốc, không tương thích với shell POSIX (như GNU bash, AT & T ksh93 , mksh). Ngoài ra, mksh gọn gàng hơn, nhanh hơn và dễ mang theo hơn.

Nói chung, nếu đây là kịch bản của bạn mà chúng tôi đang nói đến, hãy tiếp tục, chỉ cần kiểm tra chúng. . nhưng cũng sử dụng các loại dữ liệu trên mạng vì điều đó.) Nhưng nếu điều này xảy ra, giả sử, đang chạy một hệ thống Debian không có bash, hãy quên nó đi. Sự tồn tại của bash là một phần của lời hứa hẹn (API / ABI của hệ thống), và phần lớn dựa vào nó.

Tuyên bố miễn trừ trách nhiệm: Tôi là nhà phát triển mksh.


1

So sánh ZSH của Shell

Tuy nhiên, trong những năm gần đây, đã có một số lượng chéo nhất định trong các phần mở rộng. Zsh (kể từ 3.1.6) đã bash ' ${var/old/new}' feature for replacing the text old with the text new in the parameter $var. Note one difference here: while both shells implement the syntax$ {var / # old / new}' và ${var/%old/new}' for anchoring the match of old to the start or end of the parameter text, respectively, in zsh you can't put the# 'hoặc %' inside a parameter: in other words{var / $ old / new}' trong đó cũ bắt đầu bằng #' treats that as an ordinary character in zsh, unlike bash. To do this sort of thing in zsh you can use (from 3.1.7) the new syntax for anchors in any pattern,(#s) 'để khớp với bắt đầu của chuỗi và `(#e) 'để khớp với kết thúc. Những yêu cầu này tùy chọn EXTENDED_GLOB được đặt.

Tôi không quen thuộc nhất với mksh, vì vậy tôi không biết tìm câu trả lời đó ở đâu.

Nếu bạn đang tìm kiếm một sự thay thế an toàn cho shell, thì không có shell nào khác với Bash nhiều như lỗ hổng vốn có mà bạn đang thảo luận.

Một ngôn ngữ như Perl xử lý đầu vào an toàn hơn. Nhưng khả năng bảo trì cũng là chìa khóa ở đây. Việc thay thế vỏ Perl không được áp dụng tốt. Trách nhiệm của người bảo trì vỏ là xử lý an toàn đầu vào. Vì vậy, khi bạn viết kịch bản, xác nhận, xác nhận, xác nhận mọi thứ! Sử dụng hợp đồng mã để đảm bảo kết quả chính xác mỗi lần!

Vỏ Perl

Tuyên bố của FSF về Sốc Shell


Nếu đó thực sự là trường hợp các shell khác có cùng một lỗ hổng - điều mà tôi hơi nghi ngờ, dựa trên những gì đã thảo luận - thì đó là một vấn đề HẤP DẪN , bởi vì rất nhiều chương trình của bên thứ ba chuyển các biến sang shell mà không có loại nào xác nhận hoặc bất cứ điều gì. Nếu đó là trường hợp, chúng tôi cũng có thể loại bỏ hoàn toàn POSIX.
DanL4096

1
Dự án Bash đã có 1 ngày khai thác trong 10 năm. Microsoft Windows có tới 10 lần khai thác, tất cả là 0 ngày, mỗi tuần. Bạn thậm chí có biết có bao nhiêu người đã làm phiền nhóm phát triển Bash về điều này không? Chỉ cần cập nhật nó và di chuyển trên! Không có gì to tát đâu mà.
Tyler Maginnis

1
@ DanL4096. Việc chuyển các biến sang các tập lệnh shell mà sau đó không thực hiện đủ việc kiểm tra độ tỉnh táo trên các biến đó là lý do để loại bỏ POSIX. Vấn đề nằm ở người đã viết kịch bản shell ở vị trí đầu tiên.
fpmurphy

0

Một tính năng không được bật theo mặc định mkshlà lịch sử shell.

  • Trong .mkshrcbộ chỉ của bạn :

    export HISTFILE=~/.mksh-history

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.