คุณสามารถทำอะไรกับeval
คำสั่ง? ทำไมถึงมีประโยชน์ มันมีฟังก์ชั่นในตัวในการทุบตี? ไม่มีman
หน้าสำหรับมัน ..
help eval
เพื่อรับหน้า "คน" จากเปลือกของคุณ
คุณสามารถทำอะไรกับeval
คำสั่ง? ทำไมถึงมีประโยชน์ มันมีฟังก์ชั่นในตัวในการทุบตี? ไม่มีman
หน้าสำหรับมัน ..
help eval
เพื่อรับหน้า "คน" จากเปลือกของคุณ
คำตอบ:
eval
เป็นส่วนหนึ่งของ POSIX มันเป็นอินเตอร์เฟซที่สามารถเป็นเปลือกในตัว
มันอธิบายไว้ใน "คู่มือโปรแกรมเมอร์ POSIX": http://www.unix.com/man-page/posix/1posix/eval/
eval - construct command by concatenating arguments
มันจะรับอาร์กิวเมนต์และสร้างคำสั่งของมันซึ่งจะถูกดำเนินการโดยเชลล์ นี่คือตัวอย่างของ manpage:
1) foo=10 x=foo
2) y='$'$x
3) echo $y
4) $foo
5) eval y='$'$x
6) echo $y
7) 10
$foo
ด้วยค่า'10'
และมีค่า$x
'foo'
$y
เครื่องหมายดอลลาร์จะต้องหนีด้วย'$foo'
'$'
echo $y
.'$foo'
eval
ตอนนี้เราทำซ้ำที่ได้รับมอบหมายด้วย มันจะประเมินค่า$x
สตริง'foo'
ก่อน ตอนนี้เรามีคำสั่งที่จะได้รับการประเมินเพื่อy=$foo
y=10
echo $y
'10'
นี่เป็นฟังก์ชั่นทั่วไปในหลายภาษาเช่น Perl และ JavaScript ดู perldoc eval เพื่อดูตัวอย่างเพิ่มเติม: http://perldoc.perl.org/functions/eval.html
eval
เป็นแบบในตัวไม่ใช่ฟังก์ชั่น ในทางปฏิบัติบิวด์อินจะทำหน้าที่เหมือนกับฟังก์ชั่นที่ไม่มีคำจำกัดความในภาษา แต่ไม่มากeval
นัก
ใช่eval
เป็นคำสั่งภายใน bash ดังนั้นจึงได้อธิบายไว้ในbash
man page
eval [arg ...]
The args are read and concatenated together into a single com-
mand. This command is then read and executed by the shell, and
its exit status is returned as the value of eval. If there are
no args, or only null arguments, eval returns 0.
มักจะถูกนำมาใช้ร่วมกับการแทนที่คำสั่ง โดยไม่ต้องชัดเจนeval
เปลือกพยายามที่จะดำเนินการผลมาจากการแทนคำสั่งที่ไม่ประเมินมัน
VAR=value; echo $VAR
สมมติว่าคุณต้องการรหัสเทียบเท่า สังเกตความแตกต่างในวิธีที่เชลล์จัดการกับงานเขียนของecho VAR=value
:
andcoz@...:~> $( echo VAR=value )
bash: VAR=value: command not found
andcoz@...:~> echo $VAR
<empty line>
เชลล์พยายามดำเนินการecho
และVAR=value
เป็นสองคำสั่งแยกกัน มันจะโยนข้อผิดพลาดเกี่ยวกับสายที่สอง การมอบหมายดังกล่าวยังไม่มีประสิทธิภาพ
andcoz@...:~> eval $( echo VAR=value )
andcoz@...:~> echo $VAR
value
เชลล์ผสาน (เชื่อมโยง) สองสตริงecho
และVAR=value
แยกวิเคราะห์ยูนิตเดี่ยวนี้ตามกฎที่เหมาะสมและดำเนินการสุดท้าย แต่ไม่eval
ท้ายสุดอาจเป็นคำสั่งที่อันตรายมาก การป้อนeval
คำสั่งใด ๆ จะต้องตรวจสอบอย่างรอบคอบเพื่อหลีกเลี่ยงปัญหาด้านความปลอดภัย
eval
ไม่มี man page เนื่องจากไม่ใช่คำสั่งภายนอกที่แยกต่างหาก แต่เป็นเชลล์ในตัวหมายถึงคำสั่งภายในและโดยเชลล์ ( bash
) เท่านั้น ส่วนที่เกี่ยวข้องของbash
หน้าคนพูดว่า:
eval [arg ...]
The args are read and concatenated together into a single command.
This command is then read and executed by the shell, and its exit
status is returned as the value of eval. If there are no args, or only
null arguments, eval returns 0
นอกจากนี้ผลลัพธ์ถ้าhelp eval
เป็น:
eval: eval [arg ...]
Execute arguments as a shell command.
Combine ARGs into a single string, use the result as input to the shell,
and execute the resulting commands.
Exit Status:
Returns exit status of command or success if command is null.
eval
เป็นคำสั่งที่ทรงพลังและถ้าคุณตั้งใจจะใช้มันคุณควรระวังให้ดีเพื่อป้องกันความเสี่ยงที่อาจเกิดขึ้นจากการใช้งาน
คำสั่ง eval บอกให้เชลล์ใช้อาร์กิวเมนต์ของ eval เป็นคำสั่งและรันมันผ่าน command-line มันมีประโยชน์ในสถานการณ์เช่นนี้:
ในสคริปต์ของคุณหากคุณกำหนดคำสั่งให้เป็นตัวแปรและหลังจากนั้นคุณต้องการใช้คำสั่งนั้นแล้วคุณควรใช้ eval:
/home/user1 > a="ls | more"
/home/user1 > $a
bash: command not found: ls | more
/home/user1 > # Above command didn't work as ls tried to list file with name pipe (|) and more. But these files are not there
/home/user1 > eval $a
file.txt
mailids
remote_cmd.sh
sample.txt
tmp
/home/user1 >
ls | more
ในคำอื่น ๆ : ชื่อคำสั่งเดียวประกอบด้วยอักขระเก้าตัวรวมถึงช่องว่างและสัญลักษณ์ไปป์ .
eval เป็นคำสั่งเชลล์ซึ่งโดยปกติจะนำมาใช้เป็น builtin
ใน POSIX มันถูกระบุว่าเป็นส่วนหนึ่งของ "2.14. พิเศษ Built-In ยูทิลิตี้"ในรายการ"EVAL"
สิ่งที่บิวอินหมายถึงคือ:
คำว่า "ในตัว" หมายถึงว่าเชลล์สามารถรันยูทิลิตีโดยตรงและไม่จำเป็นต้องค้นหามัน
ในแง่ง่ายๆทำให้สายการป้อนข้อมูลที่จะถูกแยกเป็นสองเท่า
เชลล์มีลำดับขั้นตอนที่ตามมาเพื่อ "ประมวลผล" บรรทัด คุณสามารถดูภาพนี้และรู้ว่า eval เป็นบรรทัดเดียวที่ขึ้นไปกลับไปยังขั้นตอนที่ 1 ทางด้านซ้าย จากคำอธิบาย POSIX :
2.1 การแนะนำเชลล์
- เชลล์อ่านอินพุตของมัน ....
- เชลล์แบ่งอินพุตเป็นโทเค็น: คำและตัวดำเนินการ
- เชลล์แยกวิเคราะห์อินพุตเป็นคำสั่งแบบง่ายและแบบผสม
- เชลล์ทำการขยายที่หลากหลาย (แยกกัน) ...
- เชลล์ทำการเปลี่ยนเส้นทางและลบโอเปอเรเตอร์การเปลี่ยนเส้นทางและตัวถูกดำเนินการออกจากรายการพารามิเตอร์
- เชลล์เรียกใช้งานฟังก์ชันในตัวไฟล์ที่เรียกใช้งานได้หรือสคริปต์ ...
- เชลล์เลือกที่จะรอให้คำสั่งดำเนินการจนเสร็จสิ้นและรวบรวมสถานะการออก
ในขั้นตอนที่ 6 จะทำการประมวลผลในตัว
ในขั้นตอนที่ 6 eval ทำให้สายการประมวลผลถูกส่งกลับไปที่ขั้นตอนที่ 1
มันเป็นเงื่อนไขเดียวที่ลำดับการดำเนินการกลับไป
นั่นคือเหตุผลที่ผมบอกว่า: ด้วย EVAL สายการป้อนข้อมูลจะแยกเป็นสองเท่า
และผลกระทบที่สำคัญที่สุดที่จะเข้าใจ เป็นที่หนึ่งเป็นผลมาจากครั้งแรกบรรทัดเป็นเรื่องที่เจ็ดขั้นตอนเปลือกแสดงข้างต้นเป็นข้อความ ภายในขั้นตอนที่ 4 (การขยาย) นอกจากนี้ยังมี ลำดับขั้นตอนในการดำเนินการขยายทั้งหมดซึ่งสุดท้ายคือการลบคำพูด :
การลบคำพูดจะต้องดำเนินการครั้งสุดท้ายเสมอ
ดังนั้นจึงมีการลบข้อความหนึ่งระดับ
ผลที่ตามมาของเอฟเฟกต์แรกนั้นส่วนเพิ่มเติม / ส่วนต่าง ๆ ของบรรทัดจะถูกเปิดเผยกับการแยกวิเคราะห์เชลล์และขั้นตอนอื่น ๆ ทั้งหมด
ที่อนุญาตให้เรียกใช้งานการขยายทางอ้อม:
a=b b=c ; eval echo \$$a ### shall produce "c"
ทำไม? เพราะในวงแรกวงแรก$
จะถูกยกมา
ดังนั้นเชลล์จะถูกละเว้นสำหรับการขยายตัว
ถัดไป$
ด้วยชื่อ a ถูกขยายเพื่อสร้าง "b"
จากนั้นหนึ่งระดับของการอ้างอิงจะถูกลบออกทำให้$
unquote แรก
จุดสิ้นสุดของลูปแรก
มันเป็นแล้วในวงที่สองที่สตริง$b
จะอ่านโดยเปลือก
จากนั้นขยายไป "C" และได้รับเป็นอาร์กิวเมนต์ไปยัง
echo
หากต้องการ "ดู" สิ่งที่ eval จะสร้างในลูปแรก (เพื่อประเมินอีกครั้ง) ให้ใช้ echo หรือคำสั่ง / สคริปต์ / โปรแกรมใด ๆ ที่แสดงข้อโต้แย้งอย่างชัดเจน:
$ a=b b=c
$ eval echo \$$a;
c
แทนที่ eval ด้วย echo เพื่อ "ดู" สิ่งที่เกิดขึ้น:
$ echo echo \$$a
echo $b
นอกจากนี้ยังเป็นไปได้ที่จะแสดง "ส่วน" ทั้งหมดของบรรทัดด้วย:
$ printf '<%s> ' echo \$$a
<echo> <$b>
ซึ่งในตัวอย่างนี้เป็นเพียงเสียงสะท้อนเดียวและตัวแปรเดียว แต่จำไว้เพื่อช่วยในการประเมินกรณีที่ซับซ้อนมากขึ้น
ต้องบอกว่า: มีข้อผิดพลาดในรหัสข้างต้นคุณเห็นหรือไม่
ง่าย: มีบางคำพูดหายไป
อย่างไร? คุณอาจถาม ง่าย ๆ ลองเปลี่ยนตัวแปร (ไม่ใช่รหัส):
$ a=b b="hi jk"
$ eval echo \$$a
hi jk
เห็นช่องว่างที่หายไป?
นั่นเป็นเพราะค่าภายใน$b
ถูกแบ่งโดยเชลล์
หากสิ่งนั้นไม่ทำให้คุณมั่นใจลองสิ่งนี้:
$ a=b b="hi * jk"
$ eval echo \$$a ### warning this will expand to the list
### of all files in the present directory.
คำพูดที่ขาดหายไป เพื่อให้ทำงานได้อย่างถูกต้อง (เพิ่มคำพูดภายใน"$a"
และภายนอก\"
)
ลองนี้ (ปลอดภัยอย่างสมบูรณ์):
$ a=b b="hi * jk"
$ eval echo \" \$"$a" \"
hi * jk
ไม่มีหน้าคนสำหรับมัน ..
ไม่ไม่มีหน้าคนที่เป็นอิสระสำหรับเรื่องนี้ ค้นหาด้วยตนเองด้วยman -f eval
หรือแม้กระทั่งapropos eval
ไม่แสดงรายการ
man bash
มันรวมอยู่ภายใน เช่นเดียวกับในตัว
ค้นหา "คำสั่งเชลล์อาคาร" จากนั้นค้นหาคำว่า "eval"
วิธีที่ง่ายกว่าในการรับความช่วยเหลือคือ: ในการทุบตีคุณสามารถทำได้help eval
เพื่อดูความช่วยเหลือสำหรับการใช้งานในตัว
เพราะมันเป็นข้อความที่มีผลผูกพันกับรหัสแบบไดนามิก
กล่าวอีกนัยหนึ่ง: มันจะแปลงรายการของอาร์กิวเมนต์ (และ / หรือการขยายของอาร์กิวเมนต์ดังกล่าว) เป็นบรรทัดที่ถูกดำเนินการ หากมีเหตุผลใดก็ตามอาร์กิวเมนต์ถูกตั้งค่าโดยผู้โจมตีคุณจะเรียกใช้งานรหัสผู้โจมตี
หรือแม้แต่ง่ายขึ้นด้วย eval คุณกำลังบอกใครก็ตามที่กำหนดค่าของหนึ่งหรือหลายอาร์กิวเมนต์:
C'mon นั่งที่นี่และพิมพ์บรรทัดคำสั่งใด ๆ ฉันจะดำเนินการด้วยพลังของฉัน
มันอันตรายไหม? ควรมีความชัดเจนสำหรับทุกคนเลยก็ว่าได้
กฎความปลอดภัยสำหรับการ eval ควร:
ดำเนินการ eval เฉพาะกับตัวแปรที่คุณได้รับมันคุ้มค่า
eval
เป็นคุณลักษณะของการแปลภาษามากที่สุด (กTCL
, python
, ruby
... ) ไม่เพียง แต่เปลือกหอย มันถูกใช้เพื่อประเมินโค้ดแบบไดนามิก
ในเชลล์มันถูกใช้เป็นคำสั่ง shell builtin
โดยทั่วไปeval
รับสตริงเป็นอาร์กิวเมนต์และประเมิน / ตีความรหัสในนั้น ใน shells eval
สามารถรับได้มากกว่าหนึ่งอาร์กิวเมนต์ แต่eval
เพียงเชื่อมต่อสิ่งเหล่านั้นเพื่อสร้างสตริงเพื่อประเมิน
มีประสิทธิภาพมากเพราะคุณสามารถสร้างรหัสแบบไดนามิกและเรียกใช้สิ่งที่คุณไม่สามารถทำได้ในภาษาที่รวบรวมเช่น C
ชอบ:
varname=$1 varvalue=$2
eval "$varname=\$varvalue" # evaluate a string like "foo=$varvalue"
# which in Bourne-like shell language
# is a variable assignment.
แต่มันก็อันตรายเช่นกันเพราะมันเป็นสิ่งสำคัญที่จะต้องทำความสะอาดส่วนที่มีการพลวัต (ให้จากภายนอก) ของสิ่งที่ถูกส่งไปeval
ด้วยเหตุผลที่ถูกตีความว่าเป็นรหัสเชลล์
ตัวอย่างข้างต้นถ้า$1
เป็นevil-command; var
, eval
จะสิ้นสุดขึ้นการประเมินรหัสเปลือกแล้วเรียกว่าevil-command; var=$varvalue
evil-command
ความชั่วร้ายของeval
มักเกินความจริง
ตกลงมันเป็นอันตราย แต่อย่างน้อยเราก็รู้ว่ามันอันตราย
จำนวนมากของคำสั่งอื่น ๆ จะประเมินรหัสเปลือกในการขัดแย้งถ้าไม่ได้ปรุงแต่งเช่น (ขึ้นอยู่กับเปลือก), [
อาคาtest
, export
, printf
แอฟริกาsed
, awk
และแน่นอนsh
/ bash
/ perl
และล่ามทั้งหมด ...
ตัวอย่าง (ที่นี่ใช้uname
เป็นevil-command
และไม่$a
ได้ให้ข้อมูลที่ไม่ได้แก้ไข):
$ a='$(uname>&2)' sh -c 'eval "echo $a"'
Linux
$ a='x[0$(uname>&2)]' mksh -c 'export "$a=$b"'
Linux
$ a='x[0$(uname>&2)]' ksh93 -c 'printf "%d\n" "$a"'
Linux
0
$ a='x[0$(uname>&2)]' ksh93 -c '[ "$a" -gt 0 ]'
Linux
$ a=$'bar/g;e uname>&2\n;s//'; echo foo | sed "s/foo/$a/g"
Linux
bar
$ a='";system("uname");"'; awk "BEGIN{print \"$a\"}"
Linux
$ a=';uname'; sh -c "echo $a"
Linux
ผู้sed
, export
... คำสั่งอาจจะถือว่าเป็นอันตรายมากขึ้นเพราะในขณะที่มันเป็นที่ชัดเจนeval "$var"
จะทำให้เนื้อหาของ$var
จะได้รับการประเมินว่าเป็นรหัสเปลือกก็ไม่ชัดเจนดังนั้นมีsed "s/foo/$var/"
หรือหรือexport "$var=value"
[ "$var" -gt 0 ]
ความเป็นอันตรายนั้นเหมือนกัน แต่มันซ่อนอยู่ในคำสั่งอื่น ๆ
sed
like eval
ถูกส่งผ่านสตริงที่มีอยู่ในตัวแปรและสำหรับทั้งสองเนื้อหาของสตริงนั้นสิ้นสุดลงที่ได้รับการประเมินว่าเป็นรหัสเชลล์ดังนั้นsed
สิ่งที่อันตรายeval
ก็คือสิ่งที่ฉันพูด sed
จะถูกส่งผ่านสตริงที่มีuname
(uname ยังไม่ได้ดำเนินการจนถึง) และผ่านการร้องขอsed
คำสั่ง uname จะถูกดำเนินการ ชอบ eval ในsed 's/foo/$a/g'
คุณไม่ได้ส่งข้อมูลที่ไม่ได้รับอนุญาตถึงsed
นั่นไม่ใช่สิ่งที่เรากำลังพูดถึงที่นี่
ตัวอย่างนี้อาจทำให้เกิดแสง:
#!/bin/bash
VAR1=25
VAR2='$VAR1'
VAR3='$VAR2'
echo "$VAR3"
eval echo "$VAR3"
eval eval echo "$VAR3"
ผลลัพธ์ของสคริปต์ด้านบน:
$VAR2
$VAR1
25
eval
ตัวอย่างของการใช้ คุณเชื่อหรือไม่ว่ามีฟังก์ชั่นพื้นฐานที่สำคัญบางอย่างeval
ที่ไม่ได้กล่าวถึงในคำตอบที่มีอยู่ ถ้าเป็นเช่นนั้นให้อธิบายและใช้ตัวอย่างเพื่ออธิบายคำอธิบายของคุณ กรุณาอย่าตอบในความคิดเห็น; แก้ไข คำตอบของคุณเพื่อให้ชัดเจนและสมบูรณ์ยิ่งขึ้น
type command
เพื่อเรียนรู้ว่าคำสั่งประเภทใด (type eval
ในกรณีนี้)