รหัสไฮบริดในเชลล์สคริปต์ การแชร์ตัวแปร


10

คำตอบนี้กล่าวถึงวิธีการเรียกใช้ข้อมูลโค้ด Python หลายบรรทัดจากบรรทัดคำสั่งในเทอร์มินัล ฉันสังเกตว่าคำตอบนั้นใช้งานได้ดีในเชลล์สคริปแม้จะมีการเยื้องซ้อนกันซึ่งดีมากเช่น

#!/bin/bash
some_text="Hello world"
echo $some_text

cat <<EOF | python -
import sys;
for r in range(3):
  print r
  for a in range(2):
    print "hello"
EOF

พิมพ์:

0 
hello
hello
1
hello
hello
2
hello
hello

อย่างไรก็ตามฉันมีช่วงเวลาที่ยากลำบากในการแชร์ตัวแปรระหว่างเชลล์สคริปต์และข้อมูลโค้ดของ Python

  1. ฉันจะรวบรวมเอาต์พุตของตัวห้อย python ในสคริปต์ทุบตีได้อย่างไร (เช่นในตัวแปรเช่น$output)

  2. ฉันจะส่งตัวแปร bash (เช่น$some_text) ไปยังสคริปต์ Python ได้อย่างไร


1
คุณสามารถทำได้python - <<EOFแทน

jftr imo นี่เป็นสไตล์ที่ไม่ดีและคุณควรพยายามหลีกเลี่ยงสิ่งนั้น
Ulrich Dangel

1
ทำไมถึงแท็ก / zsh
Stéphane Chazelas

คำตอบ:


12

รับตัวแปรเป็น Python

เนื่องจาก (เมื่อไม่มีEOFเครื่องหมายอัญประกาศ) การแทนที่ตัวแปรเกิดขึ้นก่อนที่ข้อความจะถูกส่งผ่านจากอินพุต heredoc ไปpythonเป็นมาตรฐานคุณสามารถโยนตัวแปรไปทางขวาในสคริปต์

python - <<EOF
some_text = "$some_text"
EOF

ถ้าsome_textเป็นหลามจะเห็นtest some_text = "test"อย่างไรก็ตามโปรดทราบว่าสามารถมองเห็นได้ว่าเป็นช่องโหว่ในการฉีดโค้ด ถ้าsome_textเป็น"; import os; os.system("evil-command"); x = "เช่นนั้นงูหลามจะเห็นว่า:

some_text = ""; import os; os.system("evil-command"); x = ""

และเรียกใช้คำสั่งที่ชั่วร้าย

หากคุณต้องการที่จะดึงรหัส Python ของคุณลงในสคริปต์โดยไม่มีการดัดแปลงใด ๆ คุณสามารถส่งออกตัวแปรของคุณ

export some_text

และใช้os.environเพื่อดึงข้อมูล

some_text = os.environ['some_text']

นั่นเป็นวิธีที่ปลอดภัยกว่ามาก


รับเอาต์พุตจาก Python

คุณสามารถใช้การทดแทนคำสั่งเพื่อรวบรวมเอาต์พุตของสคริปต์

output=$(
python - <<EOF
import sys;
for r in range(3):
  print r
  for a in range(2):
    print "hello"
EOF
)

(โปรดทราบว่าอักขระบรรทัดใหม่ต่อท้ายทั้งหมดจะถูกลบ)


มันดูดีมาก เมื่อคุณพูด"You could also pass the variable to the script as an argument"คุณจะทำอย่างไรเมื่อพิจารณาว่าสคริปต์ Python นั้นฝังอยู่ในเชลล์สคริปต์
Amelio Vazquez-Reina

ขออภัยฉันลืมเรื่องนั้นไปหนึ่งวินาที ฉันได้ลบโซลูชันนั้นออกและเพิ่มโซลูชันที่ดีกว่า

ระวังวิธีตั้งชื่อเครื่องหมาย heredoc เมื่อไม่มีการอ้างอิงในตัวอย่างของคุณการขยายเชลล์จะเกิดขึ้นภายในสตริง heredoc ตัวอย่างเช่นถ้ารหัสไพ ธ อนของคุณประกอบด้วยเพียงแค่print '$SHELL'ผลลัพธ์จะเป็น/bin/bashหรือสิ่งที่เปลือกของคุณจะเกิดขึ้น หากคุณเปลี่ยนบรรทัดแรกที่จะส่งออกจะเป็นpython - <<'END' $SHELLหากคุณกำลังคัดลอกและวางโค้ดที่มีอยู่เพื่อฝังลงในสคริปต์ทุบตีคุณเกือบจะไม่ต้องการแทนที่เชลล์ - คุณต้องการให้โค้ดทำงานในลักษณะเดียวกับที่มันไม่ได้ฝังไว้ในสคริปต์ทุบตีใช่ไหม?
คริสจอห์นสัน

8

ปัญหาเกี่ยวกับวิธีการของคุณคือสคริปต์ python แบบฝังไม่สามารถเข้าถึง stdin ดั้งเดิมได้อีกต่อไป (เนื่องจาก stdin คือ ... ตัวเอง)

หากเป็นปัญหาคุณสามารถเขียน:

python -c '
import sys;
for r in range(3):
  print r
  for a in range(2):
    print "hello"
'

หรือถ้าสคริปต์ไพ ธ อนอาจมีเครื่องหมายคำพูดเดี่ยว:

python -c "$(cat << 'EOF'
import sys;
for r in range(3):
  print r
  for a in range(2):
    print "hello"
EOF
)"

หรือ:

python <(cat << 'EOF'
import sys;
for r in range(3):
  print r
  for a in range(2):
    print "hello"
EOF
)

6

ใช้เส้นประเป็นชื่อไฟล์:

ruby - a b <<'END'
puts ARGV.join(",")
END

python - a b <<'END'
import sys
print ",".join(sys.argv[1:])
END

ฉันไม่รู้ว่าsys.argv[1:]เป็นวิธีที่ถูกต้องใน Python หรือไม่ สำหรับ -e / -c คุณสามารถระบุจุดสิ้นสุดของอาร์กิวเมนต์ด้วย -:

set -- -a -b -c
ruby -e 'puts ARGV.join(",")' -- "$@"
python -c 'import sys; print ",".join(sys.argv[2:])' -- "$@"

การจับภาพเอาต์พุตและการเปลี่ยนเส้นทาง STDERR:

x=$(ruby <<'END' 2> /dev/null
puts "a"
abort "b"
END
)

2

1) คุณสามารถเขียนการกำหนดตัวแปรให้กับไฟล์ในไพ ธ อนจากนั้นก็ทำการบีบอัดสคริปท์ของคุณ

2) เนื่องจากไม่มีการอ้างอิงคำของคุณ (EOF) บรรทัดทั้งหมดของเอกสารที่นี่จะต้องขึ้นอยู่กับการขยายพารามิเตอร์ คุณสามารถใช้สิ่งนี้เพื่อส่งผ่านข้อมูลไปยังสคริปต์ python

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.