Chỉnh sửa tập lệnh shell trong khi nó đang chạy


91

Bạn có thể chỉnh sửa tập lệnh shell trong khi nó đang chạy và những thay đổi có ảnh hưởng đến tập lệnh đang chạy không?

Tôi tò mò về trường hợp cụ thể của một tập lệnh csh mà tôi có lô đó chạy một loạt các bản dựng khác nhau và chạy suốt đêm. Nếu có điều gì đó xảy ra với tôi giữa thao tác, tôi muốn vào và thêm các lệnh bổ sung hoặc nhận xét những lệnh chưa được thực hiện.

Nếu không thể, có bất kỳ trình bao hoặc cơ chế hàng loạt nào cho phép tôi làm điều này không?

Tất nhiên tôi đã thử nó, nhưng sẽ còn hàng giờ trước khi tôi xem nó có hoạt động hay không, và tôi tò mò về những gì đang xảy ra hoặc không xảy ra ở hậu trường.


1
Tôi đã thấy hai kết quả từ việc chỉnh sửa tệp tập lệnh cho một tập lệnh đang chạy: 1) các thay đổi bị bỏ qua như thể nó đã đọc toàn bộ vào bộ nhớ hoặc 2) tập lệnh gặp lỗi như thể nó đã đọc một phần lệnh. Tôi không biết điều đó có phụ thuộc vào kích thước của script hay không. Dù bằng cách nào, tôi sẽ không thử.
Paul Tomblin

Tóm lại: không, trừ khi nó tự tham chiếu / gọi, trong trường hợp đó, kịch bản chính sẽ vẫn là kịch bản cũ.
Wrikken

Có hai câu hỏi quan trọng ở đây. 1) Làm cách nào tôi có thể thêm chính xác và an toàn các lệnh vào tập lệnh đang chạy? 2) Khi tôi sửa đổi một tập lệnh đang chạy, điều gì sẽ xảy ra?
Chris Quenelle

3
Câu hỏi đặt ra là liệu một shell thực thi một script bằng cách đọc toàn bộ tệp script rồi thực thi nó hay bằng cách đọc một phần khi nó thực thi. Tôi không biết nó là cái nào; nó thậm chí có thể không được chỉ định. Bạn nên tránh tùy thuộc vào một trong hai hành vi.
Keith Thompson

Câu trả lời:


-67

Tập lệnh không hoạt động theo cách đó; bản sao đang thực thi độc lập với tệp nguồn mà bạn đang chỉnh sửa. Lần tới khi chạy tập lệnh, tập lệnh sẽ dựa trên phiên bản được lưu gần đây nhất của tệp nguồn.

Có thể khôn ngoan nếu chia tập lệnh này thành nhiều tệp và chạy chúng riêng lẻ. Điều này sẽ làm giảm thời gian thực hiện thất bại. (tức là, chia lô thành một tập lệnh hương vị xây dựng, chạy từng tập lệnh riêng lẻ để xem cái nào đang gây ra sự cố).


66
Tôi đã quan sát điều ngược lại. Việc chạy các tập lệnh bash được chỉnh sửa có thể khiến tập lệnh đang chạy gặp sự cố vì tệp dường như di chuyển dưới vị trí tệp đọc tập lệnh của bash.
Tilman Vogel

10
Theo kinh nghiệm của tôi trên nhiều hệ thống, bản sao thực thi KHÔNG độc lập với tệp đĩa, đó là lý do tại sao vấn đề này rất đáng ngạc nhiên và quan trọng trong lập trình tập lệnh shell.
Chris Quenelle

6
Nó chắc chắn không độc lập với tệp trên đĩa. Trình bao chỉ thường đọc các tập lệnh trong các khối, ví dụ: 128 byte hoặc 4096 byte hoặc 16384 byte và chỉ đọc khối tiếp theo khi nó cần đầu vào mới. (Bạn có thể làm những việc như lsof trên vỏ chạy một kịch bản và thấy nó vẫn còn có các tập tin mở.)
mirabilos

5
Không. Trên thực tế, nếu bạn chỉnh sửa tập lệnh, nó sẽ khiến quá trình không thành công.
Erik Aronesty

8
Bạn không chính xác. Nó được lưu vào bộ đệm tùy thuộc vào việc triển khai và lệnh thực sự đang được gọi trong tập lệnh, liệu stdout có được chuyển hướng đến một tệp hay không, có nhiều yếu tố và câu trả lời của bạn không đơn giản là chính xác.
GL2014 ngày

50

không ảnh hưởng, tại bash ít nhất là trong môi trường của tôi, nhưng trong cách rất khó chịu . Xem các mã này. Đầu tiên 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."

Làm

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

Trong trường hợp của tôi, đầu ra luôn là:

xin chào
xin chào
Đó là tất cả.
Đó là tất cả.

(Tất nhiên sẽ tốt hơn nhiều nếu tự động hóa nó, nhưng ví dụ trên có thể đọc được.)

[sửa] Điều này là không thể đoán trước, do đó nguy hiểm. Cách giải quyết tốt nhất là , như được mô tả ở đây là đặt tất cả trong một dấu ngoặc nhọn và trước dấu ngoặc nhọn đóng, hãy đặt "exit" . Đọc kỹ câu trả lời được liên kết để tránh những cạm bẫy.

[thêm] Hành vi chính xác phụ thuộc vào một dòng mới bổ sung và có lẽ cũng tùy thuộc vào hương vị Unix, hệ thống tệp của bạn, v.v. Nếu bạn chỉ muốn xem một số ảnh hưởng, chỉ cần thêm "echo foo / bar" vào b.sh trước và / hoặc sau dòng "đọc".


3
Mh, tôi không thấy tình cảm. Tui bỏ lỡ điều gì vậy?
người dùng không xác định

Hành vi chính xác phụ thuộc vào một dòng mới bổ sung , và có lẽ cũng dựa trên hương vị Unix, hệ thống tệp, v.v., không chắc ở al. Nếu bạn chỉ muốn xem bất kỳ ảnh hưởng nào, chỉ cần phóng to b.shbằng cách thêm 10 dòng echo foo / bar / baz. Ý chính của câu trả lời của dave4220 và tôi là hiệu quả không dễ dự đoán. (BTW danh từ "tình cảm" có nghĩa là "tình yêu" =)
teika kazura

vâng, nó rất hỏng. tôi có một giải pháp (bên dưới). gì thậm chí còn nguy hiểm hơn là svn / rsync / git cập nhật
Erik Aronesty

39

Hãy thử cách này ... tạo một tệp có tên bash-is-odd.sh:

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

Điều đó chứng tỏ rằng bash, thực sự, đang diễn giải script "khi bạn đi". Thật vậy, việc chỉnh sửa một kịch bản dài hạn có kết quả không thể đoán trước, chèn các ký tự ngẫu nhiên, v.v. Tại sao? Bởi vì bash đọc từ vị trí byte cuối cùng, do đó việc chỉnh sửa sẽ thay đổi vị trí của ký tự hiện tại đang được đọc.

Nói một cách ngắn gọn, Bash rất không an toàn vì "tính năng" này. svn và rsynckhi được sử dụng với các tập lệnh bash đặc biệt rắc rối, vì theo mặc định, chúng "hợp nhất" kết quả ... chỉnh sửa tại chỗ. rsynccó một chế độ sửa lỗi này. svn và git thì không.

Tôi trình bày một giải pháp. Tạo một tệp có tên /bin/bashx:

#!/bin/bash
source "$1"

Bây giờ sử dụng #!/bin/bashxtrên các tập lệnh của bạn và luôn chạy chúng bashxthay vì bash. Điều này khắc phục sự cố - bạn có thể an toàn rsynccác tập lệnh của mình.

Giải pháp thay thế (nội dòng) do @ AF7 đề xuất / thử nghiệm:

{
   # your script
} 
exit $?

Các dấu ngoặc nhọn bảo vệ khỏi các chỉnh sửa và lối ra bảo vệ chống lại sự bổ sung. Tất nhiên, tất cả chúng ta sẽ tốt hơn nhiều nếu bash đi kèm với một tùy chọn, như -w(toàn bộ tệp) hoặc thứ gì đó đã làm được điều này.


1
Btw; đây là một điểm cộng để chống lại điểm trừ và vì tôi thích câu trả lời đã chỉnh sửa của bạn.
Andrew Barber

1
Tôi không thể giới thiệu điều này. Trong cách giải quyết này, các tham số vị trí được dịch chuyển bởi một. Cũng nên nhớ rằng bạn không thể gán giá trị cho $ 0. Nó có nghĩa là nếu bạn chỉ đơn giản thay đổi "/ bin / bash" thành "/ bin / bashx", nhiều tập lệnh không thành công.
teika kazura 21/12/13

1
Xin vui lòng cho tôi biết rằng một tùy chọn như vậy đã được thực hiện rồi!
AF7

10
Một giải pháp đơn giản, được người bạn Giulio gợi ý cho tôi (các khoản tín dụng đến hạn) là chèn {ở đầu và} vào cuối scritp. Bash buộc phải đọc mọi thứ trong bộ nhớ.
AF7

1
@ AF7 cải thiện giải pháp của bạn bạn: {your_code; } && lối ra; sẽ ngăn không cho các dòng nối vào cuối cũng không được thực thi.
korkman

17

Chia tập lệnh của bạn thành các hàm và mỗi khi một hàm được gọi cho bạn sourcethì nó từ một tệp riêng biệt. Sau đó, bạn có thể chỉnh sửa tệp bất kỳ lúc nào và tập lệnh đang chạy của bạn sẽ nhận các thay đổi vào lần sau khi nó được lấy nguồn.

foo() {
  source foo.sh
}
foo

Tôi đã sử dụng kỹ thuật này một cách hiệu quả trong một thời gian để cập nhật các tập lệnh xây dựng lâu dài của tôi trong khi chúng đang chạy. Tôi muốn tìm hiểu kỹ thuật làm cho tệp hiện tại đọc cho đến cuối tệp, để tôi không cần phải có hai tệp để triển khai mỗi tập lệnh shell.
Chris Quenelle

3

Câu hỏi hay! Hy vọng tập lệnh đơn giản này sẽ giúp

#!/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"

Có vẻ như trong linux, những thay đổi được thực hiện đối với .sh đang thực thi được thực thi bởi tập lệnh đang thực thi, nếu bạn có thể nhập đủ nhanh!


2

Một lưu ý phụ thú vị - nếu bạn đang chạy một tập lệnh Python thì nó không thay đổi. (Điều này có thể hiển nhiên rõ ràng đối với bất kỳ ai hiểu cách shell chạy các tập lệnh Python, nhưng nghĩ rằng nó có thể là một lời nhắc hữu ích cho ai đó đang tìm kiếm chức năng này.)

Tôi đã tạo ra:

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

Sau đó, trong một shell khác, trong khi nó đang ngủ, hãy chỉnh sửa dòng cuối cùng. Khi điều này hoàn thành, nó hiển thị dòng không thay đổi, có lẽ vì nó đang chạy .pyc? Điều tương tự cũng xảy ra trên Ubuntu và macOS.


1

Tôi chưa cài đặt csh, nhưng

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

Chạy, chỉnh sửa nhanh dòng cuối cùng để đọc

echo Change happened

Đầu ra là

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

Hrmph.

Tôi đoán rằng các chỉnh sửa đối với các tập lệnh shell sẽ không có hiệu lực cho đến khi chúng được chạy lại.


2
bạn nên đặt chuỗi bạn muốn hiển thị trong dấu ngoặc kép.
user1463308,

2
thực ra, nó chứng tỏ rằng trình soạn thảo của bạn không hoạt động theo cách bạn nghĩ. nhiều, nhiều trình soạn thảo (bao gồm vim, emacs) hoạt động trên tệp "tmp" chứ không phải tệp trực tiếp. Hãy thử sử dụng "echo 'echo uh oh' >> myshell.sh" thay vì vi / emacs ... và xem khi nó xuất ra nội dung mới. Tệ hơn nữa ... svn và rsync cũng chỉnh sửa theo cách này!
Erik Aronesty

3
-1. Lỗi đó không liên quan đến tệp đang được chỉnh sửa: đó là do bạn đang sử dụng dấu nháy đơn! Điều đó hoạt động như một trích dẫn duy nhất, gây ra lỗi. Đặt toàn bộ chuỗi đó trong dấu ngoặc kép và thử lại.
Anonymous Penguin,

5
Thực tế là lỗi xảy ra cho thấy rằng chỉnh sửa không có hiệu quả như mong đợi.
danmcardle,

@danmcardle Ai biết không? Có lẽ bash đã thấy Change didn'ned.
Kirill Bulygin

1

Nếu tất cả điều này nằm trong một tập lệnh duy nhất, thì không, nó sẽ không hoạt động. Tuy nhiên, nếu bạn thiết lập nó như một tập lệnh trình điều khiển gọi các tập lệnh con, thì bạn có thể thay đổi một tập lệnh con trước khi nó được gọi hoặc trước khi nó được gọi lại nếu bạn đang lặp lại và trong trường hợp đó, tôi tin rằng những thay đổi đó sẽ được phản ánh trong quá trình thực hiện.


0

Tôi không nghe thấy ... nhưng còn với một số chuyển hướng:

BatchRunner.sh

Command1.sh
Command2.sh

Command1.sh

runSomething

Command2.sh

runSomethingElse

Sau đó, bạn sẽ có thể chỉnh sửa nội dung của từng tệp lệnh trước khi BatchRunner truy cập đúng không?

HOẶC LÀ

Một phiên bản rõ ràng hơn sẽ có BatchRunner xem xét một tệp duy nhất, nơi nó sẽ chạy liên tục một dòng tại một thời điểm. Sau đó, bạn sẽ có thể chỉnh sửa tệp thứ hai này trong khi tệp đầu tiên đang chạy phải không?


Tôi tự hỏi nếu nó tải chúng vào bộ nhớ để chạy chúng và một sự thay đổi không quan trọng khi quá trình chính được bắt đầu ...
Eric Hodonsky

0

Sử dụng Zsh thay thế cho tập lệnh của bạn.

AFAICT, Zsh không thể hiện hành vi khó chịu này.


Đây là lý do # 473 thích Zsh hơn để bash. Gần đây tôi đang làm việc trên một tập lệnh bash cũ mất 10 phút để chạy và tôi không thể chỉnh sửa nó trong khi chờ nó hoàn thành!
Micah Elliott

-5

thông thường, việc chỉnh sửa tập lệnh của bạn trong khi tập lệnh đang chạy là không phổ biến. Tất cả những gì bạn phải làm là kiểm tra hoạt động của mình. Sử dụng câu lệnh if / else để kiểm tra các điều kiện. Nếu một cái gì đó thất bại, sau đó làm điều này, khác làm điều đó. Đó là con đường để đi.


Nó thực sự ít về các tập lệnh bị lỗi hơn là quyết định sửa đổi hoạt động giữa các công việc hàng loạt. IE nhận ra rằng tôi muốn biên dịch nhiều hơn hoặc tôi không cần một số công việc nhất định đã có trong hàng đợi.
ack

1
Nếu bạn thực sự thêm vào các tập lệnh, thì bash sẽ làm được những gì bạn mong đợi!
Erik Aronesty
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.