ฉันกำลังเขียนเชลล์สคริปต์ที่ควรปลอดภัยเช่นไม่ส่งผ่านข้อมูลที่ปลอดภัยผ่านพารามิเตอร์ของคำสั่งและไม่ควรใช้ไฟล์ชั่วคราว ฉันจะส่งตัวแปรไปยัง stdin ของคำสั่งได้อย่างไร หรือถ้าเป็นไปไม่ได้จะใช้ไฟล์ชั่วคราวสำหรับงานดังกล่าวได้อย่างไร?
ฉันกำลังเขียนเชลล์สคริปต์ที่ควรปลอดภัยเช่นไม่ส่งผ่านข้อมูลที่ปลอดภัยผ่านพารามิเตอร์ของคำสั่งและไม่ควรใช้ไฟล์ชั่วคราว ฉันจะส่งตัวแปรไปยัง stdin ของคำสั่งได้อย่างไร หรือถ้าเป็นไปไม่ได้จะใช้ไฟล์ชั่วคราวสำหรับงานดังกล่าวได้อย่างไร?
คำตอบ:
สิ่งที่ง่ายพอ ๆ กับ:
echo "$blah" | my_cmd
echo "$blah"
ดีกว่า
blah=-n
อย่างไรblah=-e
... ใช้printf
แทนกัน unix.stackexchange.com/questions/65803/…
printf '%s\n' "$blah"
ล่ะ? ด้วยการเปลี่ยนแปลงเพียงครั้งเดียวนั้น (หลีกเลี่ยงข้อผิดพลาดมากมายในecho
ข้อกำหนดของสเปคซึ่งคำตอบที่ยอดเยี่ยมของ Stephane ได้ลงรายละเอียดไว้ที่Why is printf
better than echo
? on Unix & Linuxหรือที่ส่วน APPLICATION USAGE ของสecho
เปคสัมผัสในช่วงสั้น ๆ ) มันสมบูรณ์แบบ คำตอบที่สมเหตุสมผล
การส่งผ่านค่าไปstdin
ในbashนั้นทำได้ง่ายเพียงแค่:
your-command <<< "$your_variable"
ตรวจสอบให้แน่ใจเสมอว่าคุณใส่เครื่องหมายคำพูดรอบนิพจน์ตัวแปร!
ระมัดระวังว่านี่อาจจะทำงานเฉพาะในและจะไม่ทำงานใน
bash
sh
<<<
ไม่รับประกันว่าHerestrings จะพร้อมใช้งาน แต่ไม่ได้อยู่ในฐาน POSIX เท่าที่ฉันรู้ พวกเขาจะทำงานตามที่คาดไว้ตราบเท่าที่คุณใช้งานbash
ได้ ฉันพูดถึงมันเท่านั้นเพราะพวกเขา OP บอกว่า 'shell' ไม่ใช่เฉพาะ 'bash' แม้ว่าเขาจะติดแท็กคำถามด้วยbash
... ดังนั้นนี่จึงเป็นคำตอบที่ยอมรับได้อย่างชัดเจน
echo
วิธีนี้เนื่องจากการสร้างท่อ คำสั่งต่อไปนี้จะได้รับการประมวลผลทั้งหมดโดยbash
แม้ว่าในสถานการณ์นี้ (ตามที่ระบุไว้) คุณจะรู้ดีกว่าว่ามันจะใช้งานได้กับ bash ของคุณมิฉะนั้นข้อความแสดงข้อผิดพลาดใด ๆ ที่เกิดจากการไม่รองรับสตริงที่นี่ก็จะทำให้ข้อมูลดังกล่าวรั่วไหลเช่นกัน
echo
เป็นบิ้วอิน. ไม่มีท่อใช่มั้ย? เป็น Unix แต่ไม่สามารถเป็นUnix ได้มากขนาดนั้น
printf '%s\n' "$var"
ให้ผลลัพธ์เช่นเดียวกับecho "$var"
แต่จะไม่แตกถ้าเช่นvar=-en
และไม่จำเป็นต้องทุบตี
โปรดทราบว่าการecho "$var" | command
ดำเนินการ' หมายความว่าอินพุตมาตรฐานถูก จำกัด ไว้ที่บรรทัดที่สะท้อน หากคุณต้องการให้เชื่อมต่อเทอร์มินัลด้วยคุณจะต้องเป็นคนที่เพ้อฝันมากขึ้น:
{ echo "$var"; cat - ; } | command
( echo "$var"; cat - ) | command
ซึ่งหมายความว่าบรรทัดแรกจะเป็นเนื้อหา$var
แต่ส่วนที่เหลือจะมาจากcat
การอ่านอินพุตมาตรฐาน หากคำสั่งไม่ได้ทำอะไรที่แปลกเกินไป (ลองเปิดการแก้ไขบรรทัดคำสั่งหรือเรียกใช้เช่นvim
นั้น) ก็จะไม่เป็นไร มิฉะนั้นคุณจะต้องจินตนาการจริงๆ - ฉันคิดว่าexpect
หรืออนุพันธ์อย่างใดอย่างหนึ่งน่าจะเหมาะสม
สัญกรณ์บรรทัดคำสั่งแทบจะเหมือนกัน - แต่เซมิโคลอนที่สองจำเป็นสำหรับการจัดฟันในขณะที่ไม่ได้อยู่ในวงเล็บ
( echo "$LIST"; cat - ) | sed 1q
สิ่งนี้ใช้ได้กับฉัน แต่ฉันต้องกด ctrl d เมื่อฉันเรียกใช้สคริปต์นี้?
cat -
ยังคงอ่านจากแป้นพิมพ์จนกว่า EOF หรือขัดจังหวะดังนั้นคุณจึงจำเป็นที่จะบอกว่ามัน EOF โดยพิมพ์ควบคุม-D
cat
เลยหากคุณไม่ต้องการอินพุตเทอร์มินัลเหมือนในบรรทัดแรก หรือคุณสามารถใช้cat
เพื่อแสดงรายการไฟล์ หรือ ... ถ้าคุณต้องการให้คำสั่งอ่านอินพุตเทอร์มินัลคุณต้องบอกเมื่อมันถึงจุดสิ้นสุดของอินพุต หรือคุณสามารถใช้( echo "$var"; sed /quit/q - ) | command
; สิ่งนี้จะดำเนินต่อไปจนกว่าคุณจะพิมพ์บรรทัดที่มีคำว่า "ออก" คุณสามารถสร้างสรรค์ได้ไม่รู้จบด้วยวิธีจัดการ ระวังตำนานเมืองเก่าของโปรแกรมที่หยุดทำงานเมื่อผู้ใช้เริ่มทำงานกับเอกวาดอร์ พวกเขาจะพิมพ์ชื่อเมืองหลวงกีโตและโปรแกรมออก
echo "$LIST" | sed 1q | ...
? ทุกอย่างขึ้นอยู่กับว่าคุณเกี่ยวกับอะไร <<EOF
สัญกรณ์ควรจะต้องมีการ EOF ในช่วงเริ่มต้นของบรรทัดในที่ใดที่หนึ่งของตัวเองลงแฟ้ม ฉันไม่ได้ใช้มันฉันคิดว่า - แต่ฉันยังไม่แน่ใจว่าคุณกำลังพยายามทำอะไรอยู่ วิธีง่ายๆecho "$LIST" | command
หรือecho $LIST | command
อาจจะพอเพียงในทางปฏิบัติ (และเป็นสิ่งสำคัญที่คุณต้องรู้ถึงความสำคัญของความแตกต่างระหว่างทั้งสอง)
ฉันชอบคำตอบของมาร์ติน แต่มีปัญหาบางอย่างขึ้นอยู่กับสิ่งที่อยู่ในตัวแปร นี้
your-command <<< """$your_variable"""
จะดีกว่าถ้าคุณมีตัวแปร "หรือ!
foo1=-; foo2='"'; foo3=\!; cat<<<"$foo1"; cat<<<"$foo2"; cat<<<"$foo3"
ใช้ได้ดีสำหรับฉัน ทั้งสามคน"
ทำอะไรกันแน่? AFAIK คุณเป็นเพียงการเติมเงินล่วงหน้าและต่อท้ายสตริงว่าง
(cat <<END
$passwd
END
) | command
cat
ไม่จำเป็นจริงๆ แต่มันจะช่วยให้โครงสร้างรหัสที่ดีขึ้นและช่วยให้คุณสามารถใช้คำสั่งเพิ่มเติมในวงเล็บเป็น input เพื่อคำสั่งของคุณ
$passwd
ตามคำตอบของมาร์ตินมีคุณลักษณะทุบตีที่เรียกว่าHere Strings (ซึ่งตัวเองเป็นตัวแปรของคุณสมบัติHere Documents ที่ได้รับการสนับสนุนอย่างกว้างขวางมากขึ้น)
http://www.gnu.org/software/bash/manual/bashref.html#Here-Strings
3.6.7 นี่คือสตริง
รูปแบบของเอกสารที่นี่รูปแบบคือ:
<<< word
คำถูกขยายและป้อนให้กับคำสั่งในอินพุตมาตรฐาน
โปรดทราบว่า Here Strings ดูเหมือนจะเป็นการทุบตีเท่านั้นดังนั้นเพื่อความสะดวกในการพกพาที่ดีขึ้นคุณอาจจะดีกว่าด้วยคุณสมบัติ Here Documents ดั้งเดิมตามคำตอบของ PoltoS:
( cat <<EOF
$variable
EOF
) | cmd
หรือตัวแปรที่ง่ายกว่าจากข้างต้น:
(cmd <<EOF
$variable
EOF
)
คุณสามารถละเว้น(
และ)
เว้นแต่คุณต้องการให้สิ่งนี้เปลี่ยนเส้นทางไปยังคำสั่งอื่น ๆ เพิ่มเติม
วิธีที่ทนทานและพกพาได้นี้ได้ปรากฏในความคิดเห็น ควรเป็นคำตอบแบบสแตนด์อโลน
printf '%s' "$var" | my_cmd
หรือ
printf '%s\n' "$var" | my_cmd
หมายเหตุ:
echo
เหตุผลอยู่ที่นี่ทำไมprintf
ดีกว่าecho
?printf "$var"
มันผิด. อาร์กิวเมนต์แรกเป็นรูปแบบที่ลำดับต่าง ๆ ชอบ%s
หรือ\n
มีการตีความ ในการส่งผ่านตัวแปรไปทางขวาจะต้องไม่ตีความเป็นรูปแบบโดยปกติตัวแปรจะไม่มีบรรทัดใหม่ต่อท้าย คำสั่งเดิม (with %s
) ส่งผ่านตัวแปรตามที่เป็นอยู่ อย่างไรก็ตามเครื่องมือที่ทำงานกับข้อความอาจเพิกเฉยหรือบ่นเกี่ยวกับบรรทัดที่ไม่สมบูรณ์ (ดูเหตุใดไฟล์ข้อความจึงควรลงท้ายด้วยขึ้นบรรทัดใหม่ ) ดังนั้นคุณอาจต้องการคำสั่งหลัง (with %s\n
) ซึ่งต่อท้ายอักขระขึ้นบรรทัดใหม่ในเนื้อหาของตัวแปร ข้อเท็จจริงที่ไม่ชัดเจน:
<<<"$var" my_cmd
) ต่อท้ายบรรทัดใหม่my_cmd
แม้ว่าตัวแปรจะว่างเปล่าหรือไม่ได้กำหนดไว้ก็ตามลองสิ่งนี้:
echo "$variable" | command
echo
เป็นแบบในตัวดังนั้นจึงไม่มีกระบวนการที่จะแสดงใน ps
echo "$variable"
ดีกว่า
แค่ทำ:
printf "$my_var" | my_cmd
หาก var ไม่มีช่องว่างเครื่องหมายคำพูดอาจถูกละเว้น
หากใช้ bash คุณสามารถทำได้:
echo -n "$my_var" | my_cmd
หลีกเลี่ยงการใช้เสียงสะท้อนที่ไม่มี -n เพราะมันจะไปป์ vraiable พร้อมกับ linebreak ที่เพิ่มเข้ามาในตอนท้าย
%s
printf จะไม่พิมพ์อะไรเลย my_var="%s"; printf "$my_var";
- อาจจะลองprintf "%s" "$my_var" | my_cmd
?
$PATH
หรือไม่? ที่cat
สามารถเปลี่ยนได้/bin/cat "$@" | tee /attacker/can/read/this/file