การfor
วนซ้ำทำได้ดีที่นี่ แต่โปรดทราบว่านี่เป็นเพราะไฟล์มีชื่อเครื่องซึ่งไม่มีอักขระช่องว่างหรืออักขระกลม for x in $(cat file); do …
ไม่ทำงานเพื่อย้ำข้ามบรรทัดfile
โดยทั่วไปเพราะเชลล์แยกเอาต์พุตแรกออกจากคำสั่งcat file
ที่ใดก็ตามที่มีช่องว่างจากนั้นปฏิบัติต่อแต่ละคำว่าเป็นรูปแบบกลมดังนั้นจึง\[?*
ขยายเพิ่มเติม คุณสามารถทำให้for x in $(cat file)
ปลอดภัยถ้าคุณทำงานกับมัน:
set -f
IFS='
'
for x in $(cat file); do …
การอ่านที่เกี่ยวข้อง: วนลูปผ่านไฟล์ที่มีช่องว่างในชื่อหรือไม่ ; ฉันจะอ่านทีละบรรทัดจากตัวแปรใน bash ได้อย่างไร ; ทำไมถึงwhile IFS= read
ใช้บ่อย ๆ แทนที่จะเป็นIFS=; while read..
? โปรดทราบว่าเมื่อใช้ไวยากรณ์ปลอดภัยในการอ่านบรรทัดคือwhile read
while IFS= read -r line; do …
ทีนี้ลองมาดูว่าเกิดอะไรขึ้นกับwhile read
ความพยายามของคุณ การเปลี่ยนเส้นทางจากไฟล์รายการเซิร์ฟเวอร์ใช้กับการวนซ้ำทั้งหมด ดังนั้นเมื่อssh
รันแล้วอินพุตมาตรฐานจะมาจากไฟล์นั้น ไคลเอ็นต์ ssh ไม่ทราบว่าเมื่อใดที่แอปพลิเคชันระยะไกลอาจต้องการอ่านจากอินพุตมาตรฐาน ดังนั้นทันทีที่ไคลเอ็นต์ ssh สังเกตเห็นอินพุตบางตัวมันจะส่งอินพุตนั้นไปยังด้านรีโมต เซิร์ฟเวอร์ ssh นั้นพร้อมที่จะป้อนข้อมูลอินพุตนั้นไปยังคำสั่งรีโมตหากต้องการ ในกรณีของคุณคำสั่งระยะไกลจะไม่อ่านอินพุตใด ๆ ดังนั้นข้อมูลจะถูกยกเลิก แต่ฝั่งไคลเอ็นต์ไม่ทราบอะไรเลย ความพยายามในการecho
ทำงานของคุณเพราะecho
ไม่เคยอ่านอินพุตใด ๆ แต่จะปล่อยอินพุตมาตรฐานไว้เพียงอย่างเดียว
มีหลายวิธีที่คุณสามารถหลีกเลี่ยงปัญหานี้ได้ คุณสามารถบอก ssh ไม่ให้อ่านจากอินพุตมาตรฐานพร้อม-n
ตัวเลือก
while read server; do
ssh -n $server "uname -a"
done < /home/kenny/list_of_servers.txt
-n
ตัวเลือกในความเป็นจริงบอกจะเปลี่ยนเส้นทางการป้อนข้อมูลจากssh
/dev/null
คุณสามารถทำได้ที่ระดับเชลล์และมันจะใช้ได้กับคำสั่งใด ๆ
while read server; do
ssh $server "uname -a" </dev/null
done < /home/kenny/list_of_servers.txt
วิธีการดึงดูดการป้อนข้อมูลหลีกเลี่ยงการ SSH มาจากไฟล์ที่จะนำการเปลี่ยนเส้นทางในคำสั่ง:read
while read server </home/kenny/list_of_servers.txt; do …
สิ่งนี้จะไม่ทำงานเนื่องจากจะทำให้ไฟล์เปิดขึ้นอีกครั้งในแต่ละครั้งที่read
คำสั่งถูกเรียกใช้งาน (ดังนั้นจึงจะอ่านบรรทัดแรกของไฟล์ซ้ำไปซ้ำมา) การเปลี่ยนเส้นทางจะต้องอยู่ในขณะที่ลูปเพื่อให้ไฟล์ถูกเปิดหนึ่งครั้งในช่วงระยะเวลาของลูป
โซลูชันทั่วไปคือการจัดเตรียมอินพุตให้กับลูปบนตัวให้คำอธิบายไฟล์นอกเหนือจากอินพุตมาตรฐาน เชลล์มีโครงสร้างเพื่อข้ามฟากอินพุตและเอาต์พุตจากหมายเลข descriptor หนึ่งไปยังอีก ที่นี่เราเปิดไฟล์บน file descriptor 3 และเปลี่ยนทิศทางread
อินพุตมาตรฐานของคำสั่งจาก file descriptor 3 ไคลเอ็นต์ ssh จะละเว้น open descriptor ที่ไม่ได้มาตรฐานดังนั้นทั้งหมดจึงเป็นไปด้วยดี
while read server <&3; do
ssh $server "uname -a"
done 3</home/kenny/list_of_servers.txt
ใน bash read
คำสั่งมีตัวเลือกเฉพาะให้อ่านจาก file descriptor อื่นดังนั้นคุณสามารถเขียนread -u3 server
ได้
การอ่านที่เกี่ยวข้อง: ตัวอธิบายไฟล์ & การสคริปต์เชลล์ ; คุณจะใช้ตัวอธิบายไฟล์เพิ่มเติมเมื่อใด