การดำเนินการคำสั่งหลายบรรทัดในบรรทัดคำสั่งบรรทัดเดียว?


198

ฉันใช้ Python กับ-cเพื่อดำเนินการลูปซับหนึ่งเช่น:

$ python -c "for r in range(10): print 'rob'"

ใช้งานได้ดี อย่างไรก็ตามถ้าฉันนำเข้าโมดูลก่อน for for loop ฉันจะได้รับข้อผิดพลาดทางไวยากรณ์:

$ python -c "import sys; for r in range(10): print 'rob'"
  File "<string>", line 1
    import sys; for r in range(10): print 'rob'
              ^
SyntaxError: invalid syntax

ความคิดใด ๆ ที่สามารถแก้ไขได้?

เป็นสิ่งสำคัญสำหรับฉันที่จะใช้สิ่งนี้เป็นซับในเดียวเพื่อให้ฉันสามารถรวมไว้ใน Makefile


คำตอบ:


182

คุณสามารถทำได้

echo -e "import sys\nfor r in range(10): print 'rob'" | python

หรือท่อ w / out:

python -c "exec(\"import sys\nfor r in range(10): print 'rob'\")"

หรือ

(echo "import sys" ; echo "for r in range(10): print 'rob'") | python

หรือคำตอบของ @ SilentGhost / คำตอบของ@ Crast


ตัวเลือกสุดท้ายใช้งานได้ดีกับ python3 ใน Windows
Ian Ellis

1
@RudolfOlah หวังว่าคุณจะรู้แล้วตอนนี้ แต่สำหรับการอ้างอิงคุณต้องห่อคำสั่งการพิมพ์สำหรับ python3 + รุ่นที่ชอบ:python -c "exec(\"import sys\nfor r in range(10): print('rob')\")"
systrigger

@systrigger ขอบคุณฉันพลาดที่ฉันคิดว่าฉันกำลังรีบและไม่ทราบว่า heh

89

สไตล์นี้สามารถใช้ใน makefiles ได้เช่นกัน (และในความเป็นจริงมันถูกใช้บ่อย)

python - <<EOF
import sys
for r in range(3): print 'rob'
EOF

หรือ

python - <<-EOF
    import sys
    for r in range(3): print 'rob'
EOF

ในกรณีหลังอักขระแท็บนำหน้าจะถูกลบด้วยเช่นกัน

แทน EOF สามารถยืนคำเครื่องหมายใด ๆ ที่ไม่ปรากฏในเอกสารที่นี่ที่จุดเริ่มต้นของบรรทัด (ดูที่นี่เอกสารใน manpage ทุบตีหรือที่นี่ )


9
ดี หากต้องการส่งผ่านข้อโต้แย้งให้วางหลังจาก<<EOFนั้น อย่างไรก็ตามโปรดทราบว่าการอ้างถึงตัวคั่น - เช่น<<'EOF'- เพื่อป้องกันเนื้อหาของเอกสารที่นี่จากการขยายเชลล์ล่วงหน้า
mklement0

56

ปัญหาไม่ได้เกิดขึ้นจริงกับคำสั่งนำเข้า แต่เป็นสิ่งที่อยู่ก่อนหน้า for for loop หรือโดยเฉพาะอย่างยิ่งสิ่งใดก็ตามที่ปรากฏขึ้นก่อนที่บล็อกแบบแทรก

ตัวอย่างเช่นสิ่งเหล่านี้ทั้งหมดทำงาน:

python -c "import sys; print 'rob'"
python -c "import sys; sys.stdout.write('rob\n')"

หากการอิมพอร์ตเป็นคำสั่งเป็นปัญหานี่จะใช้งานได้ แต่จะไม่:

python -c "__import__('sys'); for r in range(10): print 'rob'"

สำหรับตัวอย่างพื้นฐานของคุณคุณสามารถเขียนซ้ำได้ดังนี้:

python -c "import sys; map(lambda x: sys.stdout.write('rob%d\n' % x), range(10))"

อย่างไรก็ตาม lambdas สามารถเรียกใช้งานนิพจน์เท่านั้นไม่ใช่ statement หรือหลาย statement ดังนั้นคุณอาจยังไม่สามารถทำสิ่งที่คุณต้องการได้ อย่างไรก็ตามระหว่างนิพจน์ตัวสร้าง, ความเข้าใจในรายการ, lambdas, sys.stdout.write, "map" builtin, และการแก้ไขบางส่วนของการสร้างสรรค์สตริงคุณสามารถทำหนึ่ง liners ที่ทรงพลัง

คำถามคือคุณต้องการไปไกลแค่ไหนและในจุดใดไม่ดีกว่าที่จะเขียน.pyไฟล์ขนาดเล็กที่ makefile ของคุณเรียกใช้งานแทน


31


- ในการทำให้คำตอบนี้ใช้งานได้กับ Python 3.xเช่นกันprintจะเรียกว่าเป็นฟังก์ชั่น : ใน 3.x จะ print('foo')ใช้ได้เฉพาะในขณะที่ 2.x ก็ยอมรับprint 'foo'เช่นกัน
- สำหรับมุมมองข้ามแพลตฟอร์มที่รวมของ Windowsดูคำตอบที่เป็นประโยชน์ kxr ของ

ในbash, kshหรือzsh :

ใช้สตริงที่ยกมา ANSI C ( $'...') ซึ่งอนุญาตให้ใช้\nเพื่อแสดงบรรทัดใหม่ที่ถูกขยายเป็นบรรทัดใหม่จริงก่อนที่สตริงจะถูกส่งผ่านไปยังpython:

python -c $'import sys\nfor r in range(10): print("rob")'

หมายเหตุ\nระหว่างimportและforคำสั่งเพื่อให้เกิดการแบ่งบรรทัด

ในการส่งค่าตัวแปรเชลล์ไปยังคำสั่งดังกล่าวจะปลอดภัยที่สุดในการใช้อาร์กิวเมนต์และเข้าถึงได้ผ่านsys.argvภายในสคริปต์ Python:

name='rob' # value to pass to the Python script
python -c $'import sys\nfor r in range(10): print(sys.argv[1])' "$name"

ดูด้านล่างสำหรับการสนทนาเกี่ยวกับข้อดีข้อเสียของการใช้สตริงคำสั่งdouble- quote (preprocessed preprocessed) พร้อมการอ้างอิงเชลล์ - ตัวแปรแบบฝัง

ในการทำงานกับ$'...'สตริงอย่างปลอดภัย:

  • \อินสแตนซ์สองเท่าในซอร์สโค้ด ต้นฉบับของคุณ
    • \<char>ลำดับ - เช่น\nในกรณีนี้ แต่ยังสงสัยปกติเช่น\t, \r, \b- มีการขยายตัว$'...'(ดูman printfสำหรับหนีสนับสนุน)
  • หนีกรณีเป็น'\'

หากคุณต้องปฏิบัติตาม POSIX :

ใช้printfกับการทดแทนคำสั่ง :

python -c "$(printf %b 'import sys\nfor r in range(10): print("rob")')"

ในการทำงานอย่างปลอดภัยกับสตริงประเภทนี้:

  • \อินสแตนซ์สองเท่าในซอร์สโค้ด ต้นฉบับของคุณ
    • \<char>ลำดับ - เช่น\nในกรณีนี้ แต่ยังสงสัยปกติเช่น\t, \r, \b- มีการขยายตัวprintf(ดูman printfสำหรับลำดับหนีสนับสนุน)
  • ผ่านการเดียวที่ยกมาสตริงprintf %bและหลบหนีฝังคำพูดเดียว '\'' (sic)

    • โดยใช้ราคาเดียวปกป้องเนื้อหาสตริงจากการตีความโดยเปลือก

      • ที่กล่าวไว้สำหรับสคริปต์ Python สั้น ๆ (เช่นในกรณีนี้) คุณสามารถใช้สตริงที่มีเครื่องหมายคำพูดคู่เพื่อรวมค่าตัวแปรของเชลล์ลงในสคริปต์ของคุณ - ตราบใดที่คุณทราบถึงข้อผิดพลาดที่เกี่ยวข้อง (ดูประเด็นต่อไป) เช่นเชลล์ขยาย$HOMEไปยัง dir บ้านของผู้ใช้ปัจจุบัน ในคำสั่งต่อไปนี้:

        • python -c "$(printf %b "import sys\nfor r in range(10): print('rob is $HOME')")"
      • อย่างไรก็ตามวิธีการที่ต้องการโดยทั่วไปคือการส่งค่าจากเชลล์ผ่านอาร์กิวเมนต์และเข้าถึงพวกมันผ่านsys.argvใน Python เทียบเท่าคำสั่งดังกล่าวคือ:

        • python -c "$(printf %b 'import sys\nfor r in range(10): print("rob is " + sys.argv[1])')" "$HOME"
    • ในขณะที่ใช้ยกมาสองครั้งสตริงมากขึ้นสะดวก - มันช่วยให้คุณใช้ฝังตัวราคาเดียวที่ไม่ใช้ Escape และฝังตัวราคาคู่เป็น\"- มันยังทำให้เรื่องสตริงกับการตีความโดยเปลือกซึ่งอาจหรือไม่อาจจะเป็นความตั้งใจ; $และ`อักขระในซอร์สโค้ดของคุณที่ไม่ได้มีไว้สำหรับเชลล์อาจทำให้เกิดข้อผิดพลาดทางไวยากรณ์หรือแก้ไขสตริงโดยไม่คาดคิด

      • นอกจากนี้การ\ประมวลผลของเชลล์เองในสตริงที่มีเครื่องหมายคำพูดคู่สามารถเข้าถึงได้ ตัวอย่างเช่นเพื่อให้Pythonสร้างเอาต์พุตตามตัวอักษรro\bคุณต้องผ่านro\\bมันไป ด้วย'...'สตริงของเชลล์และอินสแตนซ์ที่เพิ่มเป็นสองเท่า \เราจะได้รับ:
        python -c "$(printf %b 'import sys\nprint("ro\\\\bs")')" # ok: 'ro\bs'
        ในทางตรงกันข้ามสิ่งนี้ไม่ทำงานตามที่ตั้งใจไว้กับ"..."เชลล์สตริง:
        python -c "$(printf %b "import sys\nprint('ro\\\\bs')")" # !! INCORRECT: 'rs'
        เชลล์ตีความทั้งสอง "\b"และ"\\b"เป็นตัวอักษร\bต้องการจำนวน\อินสแตนซ์เพิ่มเติมเพื่อให้ได้ผลตามที่ต้องการ:
        python -c "$(printf %b "import sys\nprint('ro\\\\\\\\bs')")"

ในการส่งรหัสผ่านstdinไม่ใช่-c:

หมายเหตุ: ฉันมุ่งเน้นไปที่โซลูชันแบบบรรทัดเดียวที่นี่ คำตอบของ xorhoแสดงให้เห็นถึงวิธีการใช้เอกสารหลายบรรทัดที่นี่ - อย่าลืมอ้างอิงเครื่องหมาย เช่น<<'EOF'ยกเว้นว่าคุณต้องการให้เชลล์ขยายสตริงขึ้นด้านหน้าอย่างชัดเจน (ซึ่งมาพร้อมกับคำเตือนที่ระบุไว้ด้านบน)


ในbash, kshหรือzsh :

รวมสตริงที่ยกมา ANSI C ( $'...') กับhere-string ( <<<...):

python - <<<$'import sys\nfor r in range(10): print("rob")'

-บอกpythonอย่างชัดเจนให้อ่านจาก stdin (ซึ่งเป็นค่าเริ่มต้น) -เป็นทางเลือกในกรณีนี้ แต่ถ้าคุณต้องการส่งผ่านอาร์กิวเมนต์ไปยังสคริปต์คุณจำเป็นต้องยกเลิกการโต้แย้งอาร์กิวเมนต์จากชื่อไฟล์สคริปต์:

python - 'rob' <<<$'import sys\nfor r in range(10): print(sys.argv[1])'

หากคุณต้องปฏิบัติตาม POSIX :

ใช้printfข้างต้น แต่มีไปป์ไลน์เพื่อส่งผ่านเอาต์พุตผ่าน stdin:

printf %b 'import sys\nfor r in range(10): print("rob")' | python

ด้วยการโต้แย้ง:

printf %b 'import sys\nfor r in range(10): print(sys.argv[1])' | python - 'rob'

2
นี่ควรเป็นคำตอบที่เลือก!
เดบิวต์

1
วิธีนี้ใช้ได้ผลและอาจเป็นคำตอบที่ดีที่สุดเนื่องจากมีคำอธิบายแบบเต็มไชโย!

23

ความคิดใด ๆ ที่สามารถแก้ไขได้?

ปัญหาของคุณถูกสร้างขึ้นโดยข้อเท็จจริงที่ว่าคำสั่ง Python คั่นด้วย;ได้รับอนุญาตให้เป็น "ประโยคคำสั่งเล็ก ๆ " ซึ่งเป็นคำสั่งเดียว จากไฟล์ไวยากรณ์ในเอกสาร Python :

stmt: simple_stmt | compound_stmt
simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
small_stmt: (expr_stmt | del_stmt | pass_stmt | flow_stmt |
             import_stmt | global_stmt | nonlocal_stmt | assert_stmt)

คำสั่งผสมไม่สามารถรวมอยู่ในบรรทัดเดียวกันกับคำสั่งอื่นผ่านอัฒภาคดังนั้นการทำเช่นนี้กับ-cแฟล็กจะไม่สะดวกมาก

เมื่อสาธิต Python ในขณะที่อยู่ในสภาพแวดล้อมของ bash shell ฉันพบว่ามีประโยชน์มากในการรวมคำสั่งผสม วิธีง่ายๆในการทำสิ่งนี้อย่างน่าเชื่อถือคือ heredocs (สิ่งที่เป็น posix shell)

Heredocs

ใช้heredoc (สร้างขึ้นด้วย<<) และงูหลามตัวเลือกติดต่อบรรทัดคำสั่ง , -:

$ python - <<-"EOF"
        import sys                    # 1 tab indent
        for r in range(10):           # 1 tab indent
            print('rob')              # 1 tab indent and 4 spaces
EOF

การเพิ่ม-after <<(the <<-) อนุญาตให้คุณใช้แท็บเพื่อเยื้อง (Stackoverflow แปลงแท็บเป็นช่องว่างดังนั้นฉันจึงเว้นวรรค 8 ย่อหน้าเพื่อเน้นสิ่งนี้) แท็บนำจะถูกปล้น

คุณสามารถทำได้โดยไม่ต้องใช้แท็บเพียง<<:

$ python - << "EOF"
import sys
for r in range(10):
    print('rob')
EOF

ใส่คำพูดรอบEOFป้องกันพารามิเตอร์และการขยายตัวทางคณิตศาสตร์ สิ่งนี้ทำให้ heredoc แข็งแกร่งขึ้น

Bash สตริงหลายบรรทัด

หากคุณใช้เครื่องหมายคำพูดคู่คุณจะได้รับการขยายตัวของเชลล์:

$ python -c "
> import sys
> for p in '$PATH'.split(':'):
>     print(p)
> "
/usr/sbin
/usr/bin
/sbin
/bin
...

เพื่อหลีกเลี่ยงการขยายตัวของเชลล์ให้ใช้เครื่องหมายคำพูดเดี่ยว:

$ python -c '
> import sys
> for p in "$PATH".split(":"):
>     print(p)
> '
$PATH

โปรดทราบว่าเราต้องสลับอักขระเครื่องหมายคำพูดบนตัวอักษรใน Python - โดยทั่วไปเราไม่สามารถใช้อักขระเครื่องหมายคำพูดที่ตีความโดย BASH เราสามารถสลับมันได้เหมือนกับที่เราเห็นใน Python - แต่มันค่อนข้างสับสนอยู่แล้วซึ่งเป็นสาเหตุที่ฉันไม่แนะนำสิ่งนี้:

$ python -c '
import sys
for p in "'"$PATH"'".split(":"):
    print(p)
'
/usr/sbin
/usr/bin
/sbin
/bin
...

คำติชมของคำตอบที่ยอมรับ (และอื่น ๆ )

สิ่งนี้ไม่สามารถอ่านได้มาก:

echo -e "import sys\nfor r in range(10): print 'rob'" | python

ไม่สามารถอ่านได้มากและยากที่จะดีบักในกรณีที่เกิดข้อผิดพลาด:

python -c "exec(\"import sys\\nfor r in range(10): print 'rob'\")"

อาจอ่านได้อีกเล็กน้อย แต่ก็ยังค่อนข้างน่าเกลียด:

(echo "import sys" ; echo "for r in range(10): print 'rob'") | python

คุณจะมีช่วงเวลาที่แย่ถ้าคุณ"อยู่ในหลาม:

$ python -c "import sys
> for r in range(10): print 'rob'"

อย่าละเมิดmapหรือทำรายการความเข้าใจเพื่อให้เกิดการวนซ้ำ:

python -c "import sys; map(lambda x: sys.stdout.write('rob%d\n' % x), range(10))"

สิ่งเหล่านี้ล้วน แต่น่าเศร้าและเลว อย่าทำพวกเขา


3
++ สำหรับข้อมูลไวยากรณ์; (ไม่ขยาย) ที่นี่ doc มีประโยชน์และเป็นโซลูชั่นที่มีประสิทธิภาพที่สุด แต่เห็นได้ชัดว่าไม่ใช่ซับใน หากวิธีการแก้ปัญหาแบบบรรทัดเดียวคือต้องใช้สตริง ANSI C-ยกมา ( bash, kshหรือzsh) เป็นวิธีการแก้ปัญหาที่เหมาะสม: python -c $'import sys\nfor r in range(10): print(\'rob\')'(คุณจะมีเพียงต้องกังวลเกี่ยวกับการหลบหนีราคาเดียว (ซึ่งคุณสามารถหลีกเลี่ยงได้โดยการใช้คำพูดคู่) และ ทับขวา)
mklement0

14

เพียงใช้ return และพิมพ์ลงในบรรทัดถัดไป:

user@host:~$ python -c "import sys
> for r in range(10): print 'rob'"
rob
rob
...

6
อย่างจริงจังคุณจะแพลงบางสิ่งบางอย่างถ้าคุณทำเช่นนี้ python $(srcdir)/myscript.pyเพื่อความยุติธรรมที่ยิ่งใหญ่
Jason Orendorff

10

$ python2.6 -c "import sys; [sys.stdout.write('rob\n') for r in range(10)]"

ทำงานได้ดี ใช้ "[]" เพื่ออินไลน์ของคุณสำหรับการวนซ้ำ


8

ปัญหาไม่ได้อยู่กับimportคำสั่ง ปัญหาคือคำสั่งการควบคุมการไหลไม่ทำงานใน in line ในคำสั่ง python แทนที่นั้นimportคำแถลงด้วยคำแถลงอื่น ๆ และคุณจะเห็นปัญหาเดียวกัน

ลองคิดดูสิหลามไม่สามารถอินไลน์ทุกอย่างได้ มันใช้การเยื้องเพื่อควบคุมการไหลของกลุ่ม


7

หากระบบของคุณสอดคล้องกับ Posix.2 มันควรจะจัดหาprintfยูทิลิตี้:

$ printf "print 'zap'\nfor r in range(3): print 'rob'" | python
zap
rob
rob
rob

2
วิธีแก้ปัญหาที่ดี แต่ฉันแนะนำให้ใช้printf %b '...' | pythonสำหรับความทนทานที่เพิ่มขึ้นเพราะจะช่วยป้องกันprintfการตีความลำดับเช่น%d(ตัวระบุรูปแบบ) ในสตริงอินพุต นอกจากนี้หากคุณไม่ต้องการใช้การขยายเชลล์กับสตริงคำสั่ง Python ของคุณอย่างชัดเจน (ซึ่งอาจทำให้เกิดความสับสน) ควรใช้'(อัญประกาศเดี่ยว) สำหรับการอ้างอิงภายนอกเพื่อหลีกเลี่ยงการขยายและการแบ็กสแลชที่เชลล์ใช้ เพื่อสตริงที่ยกมาสองครั้ง
mklement0

5

single/double quotesและbackslashทุกที่:

$ python -c 'exec("import sys\nfor i in range(10): print \"bob\"")'

ดีกว่ามาก:

$ python -c '
> import sys
> for i in range(10):
>   print "bob"
> '

ดังนั้น. มาก. ดีกว่า
Marc

4

(ตอบ 23 พ.ย. 53 เวลา 19:48) ฉันไม่ใช่ Pythoner ตัวใหญ่ แต่ฉันพบไวยากรณ์ครั้งเดียวลืมที่มาฉันจึงคิดว่าฉันบันทึกไว้:

หากคุณใช้sys.stdout.writeแทนprint( ความแตกต่างเป็นsys.stdout.writeรับอาร์กิวเมนต์เป็นฟังก์ชันในวงเล็บ - แต่printไม่ได้ใช้ ) สำหรับหนึ่งซับคุณสามารถหลีกเลี่ยงการเรียงลำดับคำสั่งและforลบเซมิโคลอนออก และล้อมรอบคำสั่งในวงเล็บเหลี่ยมเช่น:

python -c "import sys; [sys.stdout.write('rob\n') for r in range(10)]"

ไม่ทราบว่าจะเรียกไวยากรณ์นี้อย่างไรใน Python :)

หวังว่าจะช่วยได้

ไชโย!


(แก้ไขอ. 9 เม.ย. 20:57:30 น. 2013)ฉันคิดว่าในที่สุดฉันก็พบว่าวงเล็บสี่เหลี่ยมจัตุรัสเหล่านี้ในแบบเส้นเดียวคืออะไร พวกเขาคือ "รายการความเข้าใจ" (ชัด); ก่อนอื่นให้สังเกตสิ่งนี้ใน Python 2.7:

$ STR=abc
$ echo $STR | python -c "import sys,re; a=(sys.stdout.write(line) for line in sys.stdin); print a"
<generator object <genexpr> at 0xb771461c>

ดังนั้นคำสั่งในวงเล็บเหลี่ยม / วงเล็บถูกมองว่าเป็น "วัตถุเครื่องกำเนิด"; ถ้าเรา "วนซ้ำ" ผ่านมันโดยการเรียกnext()- แล้วคำสั่งในวงเล็บจะถูกดำเนินการ (หมายเหตุ "abc" ในผลลัพธ์):

$ echo $STR | python -c "import sys,re; a=(sys.stdout.write(line) for line in sys.stdin); a.next() ; print a"
abc
<generator object <genexpr> at 0xb777b734>

ถ้าตอนนี้เราใช้วงเล็บเหลี่ยม - โปรดทราบว่าเราไม่จำเป็นต้องเรียกnext()เพื่อให้คำสั่งดำเนินการมันจะดำเนินการทันทีที่ได้รับมอบหมาย แต่การตรวจสอบภายหลังพบว่าaเป็นNone:

$ echo $STR | python -c "import sys,re; a=[sys.stdout.write(line) for line in sys.stdin]; print a"
abc
[None]

สิ่งนี้ไม่ได้ให้ข้อมูลมากมายที่จะมองหาสำหรับตัวยึดแบบเหลี่ยม - แต่ฉันสะดุดหน้านี้ซึ่งฉันคิดว่าอธิบาย:

Python Tips and Tricks - First Edition - Python Tutorials | Dream.In.Code :

หากคุณจำได้ว่ารูปแบบมาตรฐานของตัวสร้างบรรทัดเดียวคือประเภท 'หนึ่ง' สำหรับ 'วนรอบในวงเล็บ สิ่งนี้จะสร้าง 'iterable' one-shot 'ซึ่งเป็นวัตถุที่คุณสามารถวนซ้ำในทิศทางเดียวและคุณไม่สามารถใช้ซ้ำได้เมื่อถึงจุดสิ้นสุด

'รายการความเข้าใจ' มีลักษณะเกือบจะเหมือนกับตัวสร้างบรรทัดเดียวปกติยกเว้นว่าเครื่องหมายวงเล็บ - () - ปกติจะถูกแทนที่ด้วยวงเล็บเหลี่ยม - [] ข้อได้เปรียบที่สำคัญของการทำความเข้าใจกับเอลิสต์คือการสร้าง 'รายการ' แทนที่จะเป็นวัตถุที่น่าเบื่อ 'One-shot' เพื่อให้คุณสามารถย้อนกลับไปมาเพิ่มองค์ประกอบต่างๆเรียงลำดับ ฯลฯ

และแน่นอนมันคือรายการ - มันเป็นเพียงองค์ประกอบแรกของมันจะกลายเป็นไม่มีทันทีที่มีการดำเนินการ:

$ echo $STR | python -c "import sys,re; print [sys.stdout.write(line) for line in sys.stdin].__class__"
abc
<type 'list'>
$ echo $STR | python -c "import sys,re; print [sys.stdout.write(line) for line in sys.stdin][0]"
abc
None

ความเข้าใจในรายการมีการบันทึกไว้เป็นอย่างอื่นใน5 โครงสร้างข้อมูล: 5.1.4 รายการความเข้าใจ - เอกสาร Python v2.7.4เป็น "รายการความเข้าใจให้วิธีการสร้างรายการที่กระชับ"; สันนิษฐานว่าเป็นที่ที่ "การปฏิบัติ" ของรายการที่ จำกัด เข้ามาเล่นในหนึ่ง liners

หวังว่าฉันจะไม่ทำเครื่องหมายที่นี่มากเกินไป ...

EDIT2: และนี่คือบรรทัดคำสั่งหนึ่งซับที่มีสองไม่ซ้อนกันสำหรับลูป; ทั้งสองที่อยู่ในวงเล็บเหลี่ยม "list comprehension":

$ echo $STR | python -c "import sys,re; a=[sys.stdout.write(line) for line in sys.stdin]; b=[sys.stdout.write(str(x)) for x in range(2)] ; print a ; print b"
abc
01[None]
[None, None]

โปรดสังเกตว่าbตอนนี้"รายการ" ที่สองมีองค์ประกอบสองรายการเนื่องจากการวนซ้ำจะวิ่งสองครั้งอย่างชัดเจน แต่ผลจากการsys.stdout.write()ในทั้งสองกรณีคือ None(เห็นได้ชัด)


4

ตัวแปรนี้เป็นแบบพกพามากที่สุดสำหรับการวางสคริปต์หลายบรรทัดในบรรทัดคำสั่งบน Windows และ * nix, py2 / 3 โดยไม่ต้องไพพ์:

python -c "exec(\"import sys \nfor r in range(10): print('rob') \")"

(ไม่มีตัวอย่างอื่นที่เห็นที่นี่มาก่อน)

เรียบร้อยบน Windows คือ:

python -c exec"""import sys \nfor r in range(10): print 'rob' """
python -c exec("""import sys \nfor r in range(10): print('rob') """)

เรียบร้อยบน bash / * ระวังคือ:

python -c $'import sys \nfor r in range(10): print("rob")'

ฟังก์ชันนี้เปลี่ยนสคริปต์หลายบรรทัดให้เป็น command-one-liner แบบพกพา:

def py2cmdline(script):
    exs = 'exec(%r)' % re.sub('\r\n|\r', '\n', script.rstrip())
    print('python -c "%s"' % exs.replace('"', r'\"'))

การใช้งาน:

>>> py2cmdline(getcliptext())
python -c "exec('print \'AA\tA\'\ntry:\n for i in 1, 2, 3:\n  print i / 0\nexcept:\n print \"\"\"longer\nmessage\"\"\"')"

อินพุตคือ:

print 'AA   A'
try:
 for i in 1, 2, 3:
  print i / 0
except:
 print """longer
message"""

++ สำหรับมุมข้ามแพลตฟอร์มและตัวแปลง คำสั่งแรกของคุณเป็นสิ่งที่ดีที่จะได้รับในแง่ของการพกพา (ออกจาก PowerShell กัน) แต่ในท้ายที่สุดไม่มีเดียวที่มีประสิทธิภาพอย่างเต็มที่ไวยากรณ์ข้ามแพลตฟอร์มเพราะจำเป็นต้องใช้คำพูดคู่แล้วความเสี่ยงของการขยายเปลือกที่ไม่พึงประสงค์ด้วย Windows ต้องการการยกเว้นอักขระที่แตกต่างจากเปลือกที่คล้าย POSIX ใน PowerShell v3 หรือสูงกว่าคุณสามารถทำให้บรรทัดคำสั่งของคุณทำงานได้โดยการใส่ตัวเลือก "หยุดการแยกวิเคราะห์" --%ก่อนอาร์กิวเมนต์สตริงคำสั่ง
mklement0

@ mklement0 " การขยายเชลล์ที่ไม่ต้องการ ": การแทรกของการขยายเชลล์เข้าไปในสิ่งที่ต้องการprint "path is %%PATH%%"resp print "path is $PATH"โดยปกติจะเป็นตัวเลือกที่ต้องการในสคริปต์หรือบรรทัดคำสั่ง - เว้นแต่จะมีสิ่งหนึ่งที่สามารถหลบหนีได้ตามปกติสำหรับแพลตฟอร์ม เหมือนกับภาษาอื่น ๆ (ไวยากรณ์ของ Python นั้นไม่ได้แนะนำให้ใช้% และ $ เป็นประจำในการแข่งขัน)
kxr

หากคุณแทรกการอ้างอิงตัวแปรเชลล์ลงในซอร์สโค้ดของ Python โดยตรงโดยนิยามจะไม่สามารถพกพาได้ จุดของฉันคือว่าแม้ว่าคุณจะสร้างแทนการอ้างอิงแพลตฟอร์มเฉพาะแยกต่างหากตัวแปรที่คุณจะผ่านเป็นข้อโต้แย้งให้เป็นหนึ่งเดียว "เปลือกฟรี"คำสั่งหลามที่อาจไม่เคยทำงานเพราะคุณไม่สามารถปกป้องสตริงยกมาสองครั้งportably : เช่นถ้าคุณต้องการตัวอักษร $fooในรหัสไพ ธ อนของคุณล่ะ ถ้าคุณหนีมันเป็น\$fooเพื่อประโยชน์ของ POSIX เหมือนเปลือกหอยจะยังคงเห็นเพิ่มเติมcmd.exe \ มันอาจจะหายาก แต่มันก็คุ้มค่าที่จะรู้
mklement0

พยายามทำสิ่งนี้ใน Windows PowerShell แต่ปัญหาคือ python-c exec ("" "... " "")) ไม่ได้สร้างผลลัพธ์ใด ๆ ไม่ว่าในกรณีใดก็ตามรหัสใน ... สามารถถูกเรียกใช้งานได้ หรือไม่; ฉันสามารถพูดพล่อยๆที่นั่นและผลจะเหมือนกัน ฉันรู้สึกเหมือนเปลือกหอยคือ "การกิน" ทั้ง stdout และ stderr stream - ฉันจะทำให้มันคายออกมาได้อย่างไร
Yury

2

สคริปต์นี้มีอินเตอร์เฟสบรรทัดคำสั่งเหมือน Perl:

Pyliner - สคริปต์เพื่อเรียกใช้รหัส Python บนบรรทัดคำสั่ง (สูตร Python) โดยพลการ


ฉันคิดว่าพวกเขาต้องการสิ่งที่จะแก้ไขไม่ใช่เพื่อใช้เครื่องมืออื่น คำใบ้ที่ดีอยู่แล้ว
enrico.bacis

ฉันเห็นด้วยกับ @ enrico.bacis แต่ฉันก็ยังดีใจที่คุณเพิ่มคำตอบนี้ มันตอบคำถามที่ฉันมีเมื่อฉัน Googled หน้านี้
tbc0

1

เมื่อฉันต้องการทำสิ่งนี้ฉันใช้

python -c "$(echo -e "import sys\nsys.stdout.write('Hello World!\\\n')")"

หมายเหตุแบ็กสแลชสามรายการสำหรับบรรทัดใหม่ในคำสั่ง sys.stdout.write


งานนี้ แต่เนื่องจากคุณกำลังใช้echo -eซึ่งเป็นที่ไม่เป็นมาตรฐานและต้องbash, kshหรือzshคุณอาจรวมทั้งใช้$'...'สตริงโดยตรงซึ่งยังช่วยลดการหลบหนี:python -c $'import sys\nsys.stdout.write("Hello World!\\n")'
mklement0

คำตอบนี้ใช้งานได้คำตอบอื่น ๆ ใช้ไม่ได้กับ Python3

1

ฉันต้องการโซลูชันที่มีคุณสมบัติต่อไปนี้:

  1. อ่านง่าย
  2. อ่าน stdin เพื่อประมวลผลเอาต์พุตของเครื่องมืออื่น ๆ

ข้อกำหนดทั้งสองไม่ได้ระบุไว้ในคำตอบอื่น ๆ ดังนั้นนี่คือวิธีการอ่าน stdin ในขณะที่ทำทุกอย่างในบรรทัดคำสั่ง:

grep special_string -r | sort | python3 <(cat <<EOF
import sys
for line in sys.stdin:
    tokens = line.split()
    if len(tokens) == 4:
        print("%-45s %7.3f    %s    %s" % (tokens[0], float(tokens[1]), tokens[2], tokens[3]))
EOF
)

0

มีอีกหนึ่งตัวเลือกคือ sys.stdout.write ส่งคืน None ซึ่งทำให้รายการว่างเปล่า

cat somefile.log | python -c "import sys; [บรรทัดสำหรับบรรทัดใน sys.stdin ถ้า sys.stdout.write (บรรทัด * 2)]"


0

หากคุณไม่ต้องการสัมผัส stdin และจำลองราวกับว่าคุณผ่าน "python cmdfile.py" คุณสามารถทำสิ่งต่อไปนี้จาก bash shell:

$ python  <(printf "word=raw_input('Enter word: ')\nimport sys\nfor i in range(5):\n    print(word)")

อย่างที่คุณเห็นมันช่วยให้คุณใช้ stdin เพื่ออ่านข้อมูลอินพุต ภายในเชลล์จะสร้างไฟล์ชั่วคราวสำหรับเนื้อหาคำสั่งอินพุต


++ สำหรับไม่ใช่ "การใช้งาน" stdin พร้อมกับสคริปต์เอง (แม้ว่า-c "$(...)"จะเหมือนกันและสอดคล้องกับ POSIX) เพื่อให้<(...)สร้างชื่อ: เปลี่ยนตัวกระบวนการ ; ก็ยังทำงานในและksh zsh
mklement0
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.