ฉันจะรันสคริปต์โลคัลบนเครื่องรีโมตและรวมอาร์กิวเมนต์ได้อย่างไร?


116

ฉันได้เขียนสคริปต์ที่ทำงานได้ดีเมื่อดำเนินการภายใน:

./sysMole -time Aug 18 18

อาร์กิวเมนต์"-time" , "Aug" , "18"และ"18"ถูกส่งผ่านไปยังสคริปต์ได้สำเร็จ

ตอนนี้สคริปต์นี้ได้รับการออกแบบให้ทำงานบนเครื่องระยะไกล แต่จากไดเรกทอรีท้องถิ่นในเครื่องท้องถิ่น ตัวอย่าง:

ssh root@remoteServer "bash -s" < /var/www/html/ops1/sysMole

ที่ยังใช้งานได้ดี แต่ปัญหาเกิดขึ้นเมื่อฉันพยายามที่จะรวมข้อโต้แย้งดังกล่าว(- เวลา 18 สิงหาคม 18)ตัวอย่างเช่น:

ssh root@remoteServer "bash -s" < /var/www/html/ops1/sysMole -time Aug 18 18

หลังจากรันสคริปต์นั้นฉันได้รับข้อผิดพลาดต่อไปนี้:

bash: cannot set terminal process group (-1): Invalid argument
bash: no job control in this shell

โปรดบอกฉันว่าฉันทำอะไรผิดสิ่งนี้น่าผิดหวังอย่างมาก


1
"Bash -s" เป็นหนึ่งในวิธีที่คุณสามารถรันสคริปต์จากอินพุตมาตรฐาน (เช่นไฟล์)
AllenD

คำตอบ:


160

คุณสนิทกับตัวอย่างของคุณ มันใช้งานได้ดีเมื่อคุณใช้กับอาร์กิวเมนต์เช่นนี้

สคริปต์ตัวอย่าง:

$ more ex.bash 
#!/bin/bash

echo $1 $2

ตัวอย่างที่ใช้งานได้:

$ ssh serverA "bash -s" < ./ex.bash "hi" "bye"
hi bye

แต่มันล้มเหลวสำหรับการโต้เถียงประเภทนี้:

$ ssh serverA "bash -s" < ./ex.bash "--time" "bye"
bash: --: invalid option
...

เกิดอะไรขึ้น?

ปัญหาที่คุณกำลังประสบคือการโต้แย้ง-timeหรือในตัวอย่างของฉันจะถูกตีความว่าเป็นสวิทช์ไป--time bash -sคุณสามารถทำให้สงบbashลงได้โดยยกเลิกมันจากการรับอาร์กิวเมนต์บรรทัดคำสั่งใด ๆ ที่เหลือสำหรับตัวเองโดยใช้--อาร์กิวเมนต์

แบบนี้:

$ ssh root@remoteServer "bash -s" -- < /var/www/html/ops1/sysMole -time Aug 18 18

ตัวอย่าง

# 1:

$ ssh serverA "bash -s" -- < ./ex.bash "-time" "bye"
-time bye

# 2:

$ ssh serverA "bash -s" -- < ./ex.bash "--time" "bye"
--time bye

# 3:

$ ssh serverA "bash -s" -- < ./ex.bash --time "bye"
--time bye

# 4:

$ ssh  < ./ex.bash serverA "bash -s -- --time bye"
--time bye

หมายเหตุ:เพียงเพื่อให้ชัดเจนว่าการเปลี่ยนเส้นทางที่ปรากฏบนบรรทัดคำสั่งนั้นไม่ทำให้เกิดความแตกต่างเนื่องจากการsshเรียก remote shell ที่มีการต่อเชื่อมอาร์กิวเมนต์ของมันอยู่แล้วการ quoting ไม่ได้สร้างความแตกต่างมากนักยกเว้นเมื่อคุณต้องการ quoting บน remote shell เหมือนในตัวอย่าง# 4:

$ ssh  < ./ex.bash serverA "bash -s -- '<--time bye>' '<end>'"
<--time bye> <end>

4
คุณเป็นอัจฉริยะ! ฉันต้องทำอะไรเพื่อที่จะไปถึงระดับของคุณ? ฉันทำงานหนักมาก ขอบคุณมาก.
AllenD

14
@AllenD - เพียงแค่ถามคำถามและลองและมีส่วนร่วมในเว็บไซต์ให้มากที่สุด ฉันพยายามเรียนรู้สิ่งใหม่ทุกวัน ก่อนคำถามของคุณฉันไม่รู้ว่าจะทำสิ่งนี้ได้อย่างไร 8-) ขอบคุณสำหรับคำถามของคุณ!
slm

5
ทราบว่าการเปลี่ยนเส้นทางสามารถปรากฏที่จุดใด ๆ ในคำสั่ง: ยกตัวอย่างเช่นหรือแม้กระทั่งbash -s -- --time bye < ./ex.bash < ./ex.bash bash -s -- --time byeนี่เป็นเพราะเชลล์ใช้คำสั่งการเปลี่ยนเส้นทางครั้งแรก (โดยไม่คำนึงถึงตำแหน่งที่อยู่ในคำสั่ง) จากนั้นตั้งค่าการเปลี่ยนเส้นทางจากนั้นเรียกใช้งานส่วนที่เหลือของบรรทัดคำสั่งด้วยการเปลี่ยนเส้นทาง
lesmana

@sim ฉันพยายามทำสิ่งเดียวกันนี้ แต่จากภายในสคริปต์ไม่ใช่จากบรรทัดคำสั่ง ความคิดใด ๆ ของวิธีการทำเช่นนี้? ด้วยเหตุผลบางอย่างการใส่คำตอบที่ถูกต้องของคุณใน backticks นั้นไม่สามารถทำได้เลย มันจะรันสคริปต์ที่ระบุในเครื่องแทนและเอาต์พุตจะถูกส่งเป็นคำสั่งไปยัง bash บน ssh
krb686

@ krb686 - ฉันจะถามว่าเป็นคำถามใหม่
slm

5

ในการจัดการข้อโต้แย้งโดยพลการ

หากคุณใช้สตริงเดียวเท่านั้นจริงๆเช่น -time Aug 18 18จากนั้นคุณสามารถฮาร์ดโค้ดได้และคำตอบที่มีอยู่จะบอกวิธีการทำอย่างเพียงพอ ในทางตรงกันข้ามหากคุณต้องการส่งผ่านข้อโต้แย้งที่ไม่รู้จักผ่าน (เช่นข้อความที่จะแสดงบนระบบอื่นหรือชื่อของไฟล์ที่สร้างขึ้นที่ผู้ใช้ปลายทางสามารถควบคุมชื่อของมันได้) จำเป็นต้องใช้ความระมัดระวังมากขึ้น


ด้วยbashหรือkshเป็น/bin/sh

หากรีโมตของคุณ/bin/shจัดทำโดย bash หรือ ksh คุณสามารถทำสิ่งต่อไปนี้อย่างปลอดภัยด้วยรายการอาร์กิวเมนต์ที่ไม่น่าเชื่อถือเช่นชื่อที่เป็นอันตราย (เช่น$(rm -rf $HOME).txt) สามารถส่งผ่านเป็นอาร์กิวเมนต์ได้อย่างปลอดภัย:

runRemote() {
  local args script

  script=$1; shift

  # generate eval-safe quoted version of current argument list
  printf -v args '%q ' "$@"

  # pass that through on the command line to bash -s
  # note that $args is parsed remotely by /bin/sh, not by bash!
  ssh user@remote-addr "bash -s -- $args" < "$script"
}

กับ POSIX ใด ๆ ได้มาตรฐาน /bin/sh

เพื่อความปลอดภัยต่อข้อมูลอาร์กิวเมนต์ที่เป็นอันตรายอย่างเพียงพอ (พยายามใช้ประโยชน์จากการอ้างอิงที่ไม่เป็นไปตาม POSIX ที่ใช้โดยprintf %qใน bash เมื่อมีอักขระที่ไม่สามารถพิมพ์ได้ในสตริงที่กำลังหลบหนี) แม้ว่า/bin/shจะเป็น baseline-POSIX (เช่นdashหรือash) ก็ตาม น่าสนใจขึ้นอีกนิด:

runRemote() {
  local script=$1; shift
  local args
  printf -v args '%q ' "$@"
  ssh user@remote-addr "bash -s" <<EOF

  # pass quoted arguments through for parsing by remote bash
  set -- $args

  # substitute literal script text into heredoc
  $(< "$script")

EOF
}

การใช้งาน (สำหรับอย่างใดอย่างหนึ่งดังกล่าวข้างต้น)

ฟังก์ชั่นที่ได้รับด้านบนสามารถถูกเรียกใช้เป็น:

# if your time should be three arguments
runRemote /var/www/html/ops1/sysMole -time Aug 18 18

...หรือ...

# if your time should be one string
runRemote /var/www/html/ops1/sysMole -time "Aug 18 18"

-3

say aa เป็นไฟล์โลคัลที่มี ls

$ssh servername "cat | bash" < a.a

เปลี่ยน 127.0.0.1 เป็น ip แบบรีโมตของคุณ

สองคนนี้ให้ข้อความเกี่ยวกับการจัดสรร tty หลอก แต่พวกเขาทำงาน

$ cat a.a | ssh 127.0.0.1

$ ssh 127.0.0.1 <a.a

หรือ

$ cat a.a | ssh 127.0.0.1 bash or

$ ssh 127.0.0.1 bash < a.a


2
ฉันกำลังดิ้นรนเพื่อดูว่าคำถามนี้ตอบได้ไกลแค่ไหน
ChrisWue

คุณภาพและการจัดรูปแบบเป็นที่น่าสงสัย ฉันไม่เห็นข้อมูลที่เป็นประโยชน์ใหม่ที่ไม่ปรากฏในคำตอบที่ยอมรับเช่นกัน
Julie Pelletier

@JuliePelletier ฉันให้ตัวอย่าง 'cat' บางอย่างที่ไม่ได้รับคำตอบที่ยอมรับ มันเป็นการดีที่จะรู้วิธีทางเลือกในการทำสิ่งต่าง ๆ
barlop

นั่นไม่ใช่สิ่งที่ดี แมวของคุณไร้ประโยชน์
สกอตต์

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