แก้ไขเชลล์สคริปต์ขณะทำงาน


96

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

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

ถ้าเป็นไปไม่ได้มีเชลล์หรือชุดกลไกที่อนุญาตให้ฉันทำสิ่งนี้หรือไม่?

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


1
ฉันได้เห็นผลลัพธ์สองอย่างจากการแก้ไขไฟล์สคริปต์สำหรับสคริปต์ที่กำลังทำงานอยู่: 1) การเปลี่ยนแปลงจะถูกละเว้นราวกับว่ามันอ่านข้อมูลทั้งหมดลงในหน่วยความจำหรือ 2) สคริปต์ขัดข้องด้วยข้อผิดพลาดราวกับว่ามันอ่านส่วนหนึ่งของคำสั่งแล้ว ฉันไม่รู้ว่าขึ้นอยู่กับขนาดของสคริปต์หรือไม่ ไม่ว่าจะด้วยวิธีใดฉันจะไม่ลอง
Paul Tomblin

กล่าวโดยย่อ: ไม่เว้นแต่เป็นการอ้างอิงตัวเอง / การโทรซึ่งในกรณีนี้สคริปต์หลักจะยังคงเป็นแบบเก่า
Wrikken

มีคำถามสำคัญสองข้อที่นี่ 1) ฉันจะเพิ่มคำสั่งให้กับสคริปต์ที่กำลังทำงานได้อย่างถูกต้องและปลอดภัยได้อย่างไร? 2) เมื่อฉันแก้ไขสคริปต์ที่กำลังทำงานอยู่จะเกิดอะไรขึ้น?
Chris Quenelle

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

คำตอบ:


-69

สคริปต์ไม่ทำงานในลักษณะนั้น สำเนาการเรียกใช้งานไม่ขึ้นอยู่กับไฟล์ต้นฉบับที่คุณกำลังแก้ไข ครั้งต่อไปที่เรียกใช้สคริปต์สคริปต์จะขึ้นอยู่กับเวอร์ชันล่าสุดที่บันทึกไว้ของไฟล์ต้นฉบับ

อาจเป็นการดีที่จะแยกสคริปต์นี้ออกเป็นหลายไฟล์และเรียกใช้ทีละไฟล์ ซึ่งจะช่วยลดเวลาในการดำเนินการไปสู่ความล้มเหลว (กล่าวคือแบ่งชุดงานออกเป็นสคริปต์รสสร้างหนึ่งชุดเรียกใช้ทีละรายการเพื่อดูว่าอันใดเป็นสาเหตุของปัญหา)


68
ฉันได้สังเกตตรงข้าม การเรียกใช้สคริปต์ bash ที่ได้รับการแก้ไขอาจทำให้สคริปต์ที่กำลังทำงานล้มเหลวเนื่องจากไฟล์ดูเหมือนว่าจะย้ายไปอยู่ภายใต้ตำแหน่งไฟล์การอ่านสคริปต์ของ bash
Tilman Vogel

10
จากประสบการณ์ของฉันในหลายระบบสำเนาการเรียกใช้งานไม่ได้เป็นอิสระจากไฟล์ดิสก์นั่นเป็นเหตุผลว่าทำไมปัญหานี้จึงน่าแปลกใจและสำคัญมากในการเขียนโปรแกรมเชลล์สคริปต์
Chris Quenelle

6
แน่นอนว่ามันไม่ได้เป็นอิสระจากไฟล์บนดิสก์ โดยปกติเชลล์จะอ่านสคริปต์ในบล็อกตัวอย่างเช่น 128 ไบต์หรือ 4096 ไบต์หรือ 16384 ไบต์และอ่านเฉพาะบล็อกถัดไปเมื่อต้องการอินพุตใหม่ (คุณสามารถทำสิ่งต่างๆเช่น lsof บนเชลล์ที่เรียกใช้สคริปต์และดูว่ามันยังเปิดไฟล์อยู่)
mirabilos

5
ไม่จริงถ้าคุณแก้ไขสคริปต์มันจะทำให้กระบวนการล้มเหลว
Erik Aronesty

8
คุณไม่ถูกต้อง มันถูกบัฟเฟอร์ขึ้นอยู่กับการนำไปใช้งานและคำสั่งจริงที่ถูกเรียกในสคริปต์ไม่ว่า stdout จะถูกเปลี่ยนเส้นทางไปยังไฟล์มีหลายปัจจัยและคำตอบของคุณไม่ถูกต้อง
GL2014

52

มันไม่ส่งผลกระทบต่อที่ทุบตีน้อยในสภาพแวดล้อมของฉัน แต่ในทางที่ไม่พึงประสงค์มาก ดูรหัสเหล่านี้ อันดับแรกa.sh:

#!/bin/sh

echo "First echo"
read y

echo "$y"

echo "That's all."

b.sh:

#!/bin/sh

echo "First echo"
read y

echo "Inserted"

echo "$y"

# echo "That's all."

ทำ

$ cp a.sh run.sh
$ ./run.sh
$ # open another terminal
$ cp b.sh run.sh  # while 'read' is in effect
$ # Then type "hello."

ในกรณีของฉันผลลัพธ์คือเสมอ:

สวัสดี
สวัสดี
นั่นคือทั้งหมด
นั่นคือทั้งหมด

(แน่นอนว่ามันดีกว่าที่จะทำให้เป็นอัตโนมัติ แต่ตัวอย่างข้างต้นสามารถอ่านได้)

[แก้ไข] สิ่งนี้ไม่สามารถคาดเดาได้จึงเป็นอันตราย วิธีแก้ปัญหาที่ดีที่สุดคือ , ตามที่อธิบายไว้ที่นี่ ใส่ทั้งหมดในรั้งและก่อนที่จะรั้งปิดใส่ออก "" อ่านคำตอบที่เชื่อมโยงให้ดีเพื่อหลีกเลี่ยงข้อผิดพลาด

[เพิ่ม] พฤติกรรมที่แน่นอนขึ้นอยู่กับการขึ้นบรรทัดใหม่หนึ่งบรรทัดและอาจขึ้นอยู่กับรสชาติของ Unix ระบบไฟล์ ฯลฯ หากคุณต้องการเห็นอิทธิพลบางอย่างเพียงแค่เพิ่ม "echo foo / bar" ลงใน b.sh ก่อนและ / หรือหลัง บรรทัด "อ่าน"


3
ฉันไม่เห็นความเสน่หา ฉันพลาดอะไรไปรึเปล่า?
ไม่ทราบผู้ใช้

พฤติกรรมที่แน่นอนขึ้นอยู่กับการขึ้นบรรทัดใหม่หนึ่งบรรทัดและอาจจะขึ้นอยู่กับรสชาติของ Unix ระบบไฟล์ ฯลฯ คิดว่าไม่แน่ใจที่ al หากคุณต้องการดูอิทธิพลใด ๆ เพียงแค่ขยายขนาดb.shโดยเพิ่ม echo foo / bar / baz 10 บรรทัด ส่วนสำคัญของคำตอบโดย dave4220 และฉันคือผลที่คาดเดาได้ไม่ยาก (BTW คำนาม "เสน่หา" แปลว่า "รัก" =)
teika kazura

ใช่มันพังมาก ฉันมีวิธีแก้ไข (ด้านล่าง) สิ่งที่อันตรายยิ่งกว่าคือการอัปเดต svn / rsync / git
Erik Aronesty

40

ลองสิ่งนี้ ... สร้างไฟล์ชื่อbash-is-odd.sh:

#!/bin/bash
echo "echo yes i do odd things" >> bash-is-odd.sh

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

Bash เป็นคำที่ไม่ปลอดภัยมากเนื่องจาก "คุณลักษณะ" นี้ svn และrsyncเมื่อใช้กับ bash scripts เป็นเรื่องที่น่าหนักใจเป็นพิเศษเพราะโดยค่าเริ่มต้นพวกเขาจะ "รวม" ผลลัพธ์ ... แก้ไขในสถานที่ rsyncมีโหมดที่แก้ไขปัญหานี้ svn และ git ไม่ได้

ฉันนำเสนอวิธีแก้ปัญหา สร้างไฟล์ชื่อ/bin/bashx:

#!/bin/bash
source "$1"

ตอนนี้ใช้#!/bin/bashxในสคริปต์ของคุณและมักจะเรียกพวกเขากับแทนbashx bashวิธีนี้ช่วยแก้ปัญหา - คุณสามารถrsyncใช้สคริปต์ของคุณได้อย่างปลอดภัย

โซลูชันทางเลือก (ในบรรทัด) ที่เสนอ / ทดสอบโดย @ AF7:

{
   # your script
} 
exit $?

วงเล็บปีกกาป้องกันการแก้ไขและทางออกป้องกันการต่อท้าย แน่นอนว่าเราทุกคนจะดีขึ้นมากถ้า bash มาพร้อมกับตัวเลือกเช่น-w(ทั้งไฟล์) หรือบางอย่างที่ทำเช่นนี้


1
Btw; นี่คือข้อดีในการตอบโต้การลบและเพราะฉันชอบคำตอบที่คุณแก้ไข
Andrew Barber

1
ฉันไม่สามารถแนะนำสิ่งนี้ได้ ในวิธีแก้ปัญหานี้พารามิเตอร์ตำแหน่งจะถูกเลื่อนไปทีละรายการ โปรดจำไว้ว่าคุณไม่สามารถกำหนดมูลค่าเป็น $ 0 ได้ หมายความว่าหากคุณเพียงแค่เปลี่ยน "/ bin / bash" เป็น "/ bin / bashx" สคริปต์จำนวนมากจะล้มเหลว
teika kazura

1
โปรดบอกฉันว่าตัวเลือกดังกล่าวได้ถูกนำมาใช้แล้ว!
AF7

10
วิธีง่ายๆที่เพื่อนของฉัน Giulio แนะนำให้ฉัน (เครดิตที่ครบกำหนด) คือการแทรก {at the beginning and} ที่ส่วนท้ายของ scritp แบชถูกบังคับให้อ่านทุกอย่างในความทรงจำ
AF7

1
@ AF7 ปรับปรุงโซลูชันของเพื่อน: {your_code; } && ออก; จะป้องกันไม่ให้บรรทัดที่ต่อท้ายท้ายถูกดำเนินการเช่นกัน
korkman

17

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

foo() {
  source foo.sh
}
foo

ฉันใช้เทคนิคนี้อย่างมีประสิทธิภาพมาระยะหนึ่งแล้วเพื่ออัปเดตสคริปต์บิลด์ที่ใช้งานมายาวนานในขณะที่กำลังทำงานอยู่ ฉันชอบที่จะเรียนรู้เทคนิคในการทำให้ไฟล์ปัจจุบันอ่านจนจบไฟล์เพื่อที่ฉันจะได้ไม่ต้องมีสองไฟล์เพื่อใช้งานเชลล์สคริปต์แต่ละอัน
Chris Quenelle

3

คำถามที่ดี! หวังว่าสคริปต์ง่ายๆนี้จะช่วยได้

#!/bin/sh
echo "Waiting..."
echo "echo \"Success! Edits to a .sh while it executes do affect the executing script! I added this line to myself during execution\"  " >> ${0}
sleep 5
echo "When I was run, this was the last line"

ดูเหมือนว่าภายใต้ linux จะมีการเปลี่ยนแปลงที่เกิดขึ้นกับการเรียกใช้งาน. sh ถูกตราขึ้นโดยสคริปต์การดำเนินการหากคุณสามารถพิมพ์ได้เร็วพอ!


2

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

ฉันสร้าง:

#!/usr/bin/env python3
import time
print('Starts')
time.sleep(10)
print('Finishes unchanged')

จากนั้นในเชลล์อื่นในขณะที่อยู่ในโหมดสลีปให้แก้ไขบรรทัดสุดท้าย เมื่อดำเนินการเสร็จสิ้นจะแสดงบรรทัดที่ไม่เปลี่ยนแปลงซึ่งน่าจะเป็นเพราะกำลังเรียกใช้ a .pyc? สิ่งเดียวกันนี้เกิดขึ้นกับ Ubuntu และ macOS


1

ฉันไม่ได้ติดตั้ง csh แต่

#!/bin/sh
echo Waiting...
sleep 60
echo Change didn't happen

เรียกใช้แก้ไขบรรทัดสุดท้ายอย่างรวดเร็วเพื่ออ่าน

echo Change happened

เอาต์พุตคือ

Waiting...
/home/dave/tmp/change.sh: 4: Syntax error: Unterminated quoted string

ชม.

ฉันเดาว่าการแก้ไขเชลล์สคริปต์จะไม่มีผลจนกว่าจะรันใหม่


2
คุณควรใส่สตริงที่คุณต้องการแสดงในเครื่องหมายคำพูด
user1463308

2
อันที่จริงมันพิสูจน์ได้ว่าตัวแก้ไขของคุณไม่ได้ทำงานอย่างที่คุณคิด บรรณาธิการจำนวนมาก (รวมทั้ง vim, emacs) ทำงานบนไฟล์ "tmp" ไม่ใช่ไฟล์สด ลองใช้ "echo" echo uh oh ">> myshell.sh" แทน vi / emacs ... และดูขณะที่ส่งออกสิ่งใหม่ แย่กว่านั้น ... svn และ rsync ก็แก้ไขด้วยวิธีนี้!
Erik Aronesty

3
-1. ข้อผิดพลาดนั้นไม่เกี่ยวข้องกับไฟล์ที่กำลังแก้ไขนั่นเป็นเพราะคุณใช้เครื่องหมายวรรคตอน! ซึ่งทำหน้าที่เป็นเครื่องหมายคำพูดเดียวทำให้เกิดข้อผิดพลาด ใส่ทั้งสตริงในเครื่องหมายคำพูดคู่แล้วลองอีกครั้ง
เพนกวินนิรนาม

5
ความจริงที่เกิดข้อผิดพลาดแสดงว่าการแก้ไขไม่มีผลตามที่ตั้งใจไว้
danmcardle

@danmcardle ใครรู้บ้าง Change didn'nedเลื่อยทุบตีบางที
Kirill Bulygin

1

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


0

ฉันไม่ได้ยิน ... แต่สิ่งที่เกี่ยวกับทิศทาง:

BatchRunner.sh

Command1.sh
Command2.sh

Command1.sh

runSomething

Command2.sh

runSomethingElse

จากนั้นคุณควรจะสามารถแก้ไขเนื้อหาของแต่ละไฟล์คำสั่งก่อนที่ BatchRunner จะเข้าถึงได้ใช่ไหม?

หรือ

เวอร์ชันที่สะอาดกว่าจะทำให้ BatchRunner มองไปที่ไฟล์เดียวซึ่งจะทำงานต่อเนื่องกันทีละบรรทัด จากนั้นคุณควรจะสามารถแก้ไขไฟล์ที่สองนี้ได้ในขณะที่ไฟล์แรกกำลังทำงานอยู่ใช่ไหม?


ฉันสงสัยว่ามันโหลดลงในหน่วยความจำเพื่อเรียกใช้หรือไม่และการเปลี่ยนแปลงไม่สำคัญเมื่อกระบวนการหลักเริ่มต้นขึ้น ...
Eric Hodonsky

0

ใช้ Zsh แทนการเขียนสคริปต์ของคุณ

AFAICT, Zsh ไม่แสดงพฤติกรรมที่น่าหงุดหงิดนี้


นี่คือเหตุผลที่ # 473 ชอบให้ Zsh ทุบตี ฉันเพิ่งทำงานกับสคริปต์ทุบตีเก่าที่ใช้เวลา 10m ในการรันและฉันไม่สามารถแก้ไขได้ในขณะที่รอให้มันเสร็จสมบูรณ์!
Micah Elliott

-5

โดยปกติแล้วการแก้ไขสคริปต์ของคุณในขณะที่กำลังทำงานเป็นเรื่องปกติ สิ่งที่คุณต้องทำคือควบคุมตรวจสอบการปฏิบัติงานของคุณ ใช้คำสั่ง if / else เพื่อตรวจสอบเงื่อนไข หากมีบางอย่างล้มเหลวให้ทำเช่นนั้นให้ทำอย่างอื่น นั่นคือวิธีที่จะไป


จริงๆแล้วสคริปต์ล้มเหลวน้อยกว่าการตัดสินใจแก้ไขชุดงานระหว่างการดำเนินการ IE ตระหนักว่าฉันต้องการรวบรวมมากกว่านี้หรือฉันไม่ต้องการงานบางอย่างในคิวแล้ว
ack

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