Çalışırken kabuk komut dosyasını düzenleyin


95

Bir kabuk komut dosyasını çalışırken düzenleyebilir ve değişikliklerin çalışan komut dosyasını etkilemesini sağlayabilir misiniz?

Sahip olduğum bir csh betiğinin özel durumunu merak ediyorum, bu toplu iş bir sürü farklı yapı çeşidi çalıştırıyor ve bütün gece çalışıyor. İşlemin ortasında bana bir şey olursa, içeri girip ek komutlar eklemek veya yürütülmemiş olanları yorumlamak istiyorum.

Mümkün değilse, bunu yapmama izin verecek herhangi bir kabuk veya parti mekanizması var mı?

Tabii ki denedim, ancak işe yarayıp yaramadığını görmeden önce saatler alacak ve perde arkasında neler olup bittiğini merak ediyorum.


1
Çalışan bir betik için betik dosyasını düzenlemekten iki sonuç gördüm: 1) Değişiklikler sanki her şeyi belleğe okumuş gibi göz ardı edilir veya 2) betik, komutun bir bölümünü okumuş gibi bir hatayla çöker. Bunun senaryonun boyutuna bağlı olup olmadığını bilmiyorum. Her iki durumda da denemem.
Paul Tomblin

Kısaca: hayır, kendi kendine referans / arama olmadığı sürece, bu durumda ana komut dosyası hala eski olacaktır.
Wrikken

Burada iki önemli soru var. 1) Çalışan bir betiğe komutları nasıl doğru ve güvenli bir şekilde ekleyebilirim? 2) Çalışan bir komut dosyasını değiştirdiğimde ne olur?
Chris Quenelle

3
Soru, bir kabuğun bir komut dosyasını tüm komut dosyası dosyasını okuyarak ve ardından çalıştırarak mı yoksa yürütürken kısmen okuyarak mı yürüttüğüdür. Hangisi olduğunu bilmiyorum; belirtilmemiş bile olabilir. Her iki davranıştan da kaçınmalısınız.
Keith Thompson

Yanıtlar:


-68

Komut dosyaları bu şekilde çalışmaz; çalıştırılan kopya, düzenlemekte olduğunuz kaynak dosyadan bağımsızdır. Komut dosyası bir sonraki çalıştırılışında, kaynak dosyanın en son kaydedilen sürümünü temel alacaktır.

Bu betiği birden çok dosyaya ayırıp ayrı ayrı çalıştırmak akıllıca olabilir. Bu, yürütme süresini başarısız olacak şekilde azaltacaktır. (yani, toplu işi bir yapı çeşidi komut dosyalarına bölün, hangisinin soruna neden olduğunu görmek için her birini ayrı ayrı çalıştırın).


68
Ben tam tersini gözlemledim. Düzenlenen bash komut dosyalarını çalıştırmak, çalışan komut dosyasının çökmesine neden olabilir çünkü dosya, bash'ın komut dosyası okuma dosya konumu altında hareket ediyor gibi görünüyor.
Tilman Vogel

10
Birden fazla sistemdeki deneyimime göre, kopyayı çalıştırmak disk dosyasından bağımsız DEĞİLDİR, bu nedenle bu sorun kabuk betiği programlamasında çok şaşırtıcı ve önemlidir.
Chris Quenelle

6
Kesinlikle disk üzerindeki dosyadan bağımsız değildir . Kabuk genellikle komut dosyalarını örneğin 128 bayt veya 4096 bayt veya 16384 baytlık bloklar halinde okur ve yalnızca yeni girişe ihtiyaç duyduğunda sonraki bloğu okur. (Bir komut dosyası çalıştıran bir kabukta lsof gibi şeyler yapabilirsiniz ve dosyanın hala açık olduğunu görebilirsiniz.)
mirabilos

5
Hayır. Aslında bir komut dosyasını düzenlerseniz işlemin başarısız olmasına neden olur.
Erik Aronesty

8
Doğru değilsin Uygulamaya ve komut dosyasında çağrılan gerçek komuta bağlı olarak arabelleğe alınır, stdout bir dosyaya yönlendirilsin, birçok faktör vardır ve cevabınız basitçe doğru değildir.
GL2014

51

Bu mu benim ortamında en az partisinde, ama içinde, etkileyebilecek çok tatsız bir şekilde . Bu kodlara bakın. İlk olarak 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."

Yapmak

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

Benim durumumda, çıktı her zaman:

Merhaba
Merhaba
Bu kadar.
Bu kadar.

(Elbette otomatikleştirmek çok daha iyidir, ancak yukarıdaki örnek okunabilir.)

[değiştir] Bu tahmin edilemez, dolayısıyla tehlikelidir. En iyi çözüm olduğunu , burada açıklandığı şekilde bir kuşak tüm koyun ve Kapanış ayracı önce "exit" koydu . Tuzaklardan kaçınmak için bağlantılı cevabı iyice okuyun .

[eklendi] Tam davranış, fazladan bir satıra ve belki de Unix çeşidinize, dosya sisteminize vb. bağlıdır. Yalnızca bazı etkileri görmek istiyorsanız, b.sh'den önce ve / veya sonra "echo foo / bar" ekleyin. "oku" satırı.


3
Mh, sevgiyi görmüyorum. Bir şey mi kaçırıyorum?
kullanıcı bilinmeyen

Kesin davranış, fazladan bir satırsonu satırına ve belki de Unix çeşidine, dosya sistemine vb. Herhangi bir etkiyi görmek istiyorsanız, b.sh10 satır echo foo / bar / baz ekleyerek büyütmeniz yeterlidir . Dave4220 ve benim tarafımızca verilen cevapların özü, etkinin tahmin edilmesinin kolay olmamasıdır. (BTW adı "sevgi", "aşk" anlamına gelir =)
teika kazura

evet, çok bozuk. bir çözümüm var (aşağıda). daha da tehlikeli olan svn / rsync / git güncellemeleri
Erik Aronesty

40

Bunu deneyin ... adlı bir dosya oluşturun bash-is-odd.sh:

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

Bu, bash'ın senaryoyu "ilerledikçe" yorumladığını gösteriyor. Gerçekten de, uzun süredir çalışan bir komut dosyasını düzenlemenin tahmin edilemeyen sonuçları, rastgele karakterler eklenmesi vb. Bash son bayt konumundan okuduğundan, düzenleme, okunmakta olan geçerli karakterin konumunu değiştirir.

Bash, bu "özellik" nedeniyle tek kelimeyle çok çok güvensizdir. svn versync bash betikleri ile birlikte kullanıldığında özellikle rahatsız edicidir, çünkü varsayılan olarak sonuçları "birleştirirler" ... yerinde düzenleme. rsyncbunu düzelten bir moda sahiptir. svn ve git yok.

Bir çözüm sunuyorum. Şu adla bir dosya oluşturun /bin/bashx:

#!/bin/bash
source "$1"

Şimdi #!/bin/bashxkomut dosyalarınızda kullanın ve bunları her zaman bashxyerinebash . Bu, sorunu çözer - rsynckomut dosyalarınızı güvenle yapabilirsiniz .

@ AF7 tarafından önerilen / test edilen alternatif (sıralı) çözüm:

{
   # your script
} 
exit $?

Kıvırcık ayraçlar düzenlemelere karşı koruma sağlar ve çıkış, eklemelere karşı koruma sağlar. Tabii ki, bash -w(tüm dosya) veya bunu yapan bir şey gibi bir seçenekle gelirse hepimiz çok daha iyi durumda oluruz .


1
Btw; işte eksiye karşı bir artı ve çünkü sizin düzenlenmiş cevabınızı beğendim.
Andrew Barber

1
Bunu tavsiye edemem. Bu geçici çözümde, konumsal parametreler birer birer kaydırılır. Ayrıca $ 0'a bir değer atayamayacağınızı da unutmayın. Bu, "/ bin / bash" ı "/ bin / bashx" olarak değiştirirseniz, birçok betik başarısız olur.
teika kazura

1
Lütfen bana böyle bir seçeneğin zaten uygulandığını söyleyin!
AF7

10
Arkadaşım Giulio tarafından bana önerilen basit bir çözüm (gerekli olduğu durumlarda kredi), scritp'in başına {ve} 'yi eklemektir. Bash hafızadaki her şeyi okumaya zorlanır.
AF7

1
@ AF7, arkadaşınızın çözümünde gelişiyor: {kodunuz; } && çıkış; sonuna eklenen satırların da yürütülmesini engelleyecektir.
korkman

17

Komut dosyanızı işlevlere ayırın ve her işlev size sourceayrı bir dosyadan çağrıldığında . Ardından, dosyaları istediğiniz zaman düzenleyebilirsiniz ve çalışan komut dosyanız, bir sonraki kaynak sağlandığında değişiklikleri alır.

foo() {
  source foo.sh
}
foo

Uzun süredir çalışan derleme komut dosyalarımı çalışırken güncellemek için bu tekniği bir süredir etkili bir şekilde kullanıyorum. Mevcut dosyanın dosyanın sonuna kadar okunmasını sağlayacak bir teknik öğrenmeyi çok isterim, böylece her bir kabuk betiğini uygulamak için iki dosyaya ihtiyacım olmaz.
Chris Quenelle

3

İyi soru! Umarım bu basit komut dosyası yardımcı olur

#!/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 altında, eğer yeterince hızlı yazabiliyorsanız, çalıştırılan bir .sh dosyasında yapılan değişiklikler, yürütme betiği tarafından gerçekleştiriliyor gibi görünüyor!


2

İlginç bir yan not - bir Python betiği çalıştırıyorsanız, bu değişmez. (Bu, kabuğun Python komut dosyalarını nasıl çalıştırdığını anlayan herkes için muhtemelen bariz bir şekilde açıktır, ancak bu işlevi arayan biri için yararlı bir hatırlatma olabileceğini düşünmüştür.)

Ben YARATTIM:

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

Sonra başka bir kabukta, bu uyurken son satırı düzenleyin. Bu tamamlandığında, muhtemelen bir .pyc? Çalıştırdığı için değiştirilmemiş satırı görüntüler. Aynı şey Ubuntu ve macOS'ta da oluyor.


1

Yüklü csh'ım yok ama

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

Çalıştırın, okumak için son satırı hızlıca düzenleyin

echo Change happened

Çıktı

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

Hrmph.

Sanırım kabuk komut dosyalarında yapılan düzenlemeler yeniden çalıştırılıncaya kadar etkili olmayacak.


2
Görüntülemek istediğiniz dizeyi tırnak içine almalısınız.
user1463308

2
aslında, editörünüzün düşündüğünüz gibi çalışmadığını kanıtlıyor. birçok düzenleyici (vim, emacs dahil) canlı dosya üzerinde değil "tmp" dosyası üzerinde çalışır. Vi / emacs yerine "echo 'echo uh oh' >> myshell.sh" kullanmayı deneyin ... ve yeni şeylerin çıktılarını verirken izleyin. Daha kötüsü ... svn ve rsync de bu şekilde düzenler!
Erik Aronesty

3
-1. Bu hata, düzenlenmekte olan dosyayla ilgili değildir: kesme işareti kullandığınız içindir! Bu, hataya neden olan tek bir alıntı görevi görür. Tüm dizeyi çift tırnak içine alın ve tekrar deneyin.
Anonim Penguen

5
Hatanın meydana gelmesi, düzenlemenin istenen etkiye sahip olmadığını gösterir.
danmcardle

@danmcardle Kim bilir? Belki Bash gördü Change didn'ned.
Kirill Bulygin

1

Bunların hepsi tek bir komut dosyasındaysa, hayır çalışmayacaktır. Bununla birlikte, alt komut dosyalarını çağıran bir sürücü komut dosyası olarak ayarlarsanız, alt komut dosyasını çağrılmadan önce veya döngü yapıyorsanız tekrar çağrılmadan önce değiştirebilirsiniz ve bu durumda bu değişikliklere inanıyorum. yürütmeye yansıyacaktır.


0

Hayır duyuyorum ... ama biraz dolaylı olarak:

BatchRunner.sh

Command1.sh
Command2.sh

Command1.sh

runSomething

Command2.sh

runSomethingElse

O halde, BatchRunner doğru şekilde ulaşmadan önce her komut dosyasının içeriğini düzenleyebilmelisiniz?

VEYA

Daha temiz bir sürüm, BatchRunner'ın her seferinde arka arkaya bir satır çalıştıracağı tek bir dosyaya bakmasını sağlar. Öyleyse, ilk dosya çalışırken bu ikinci dosyayı düzenleyebilmelisiniz?


Acaba onları çalıştırmak için hafızaya yüklüyor mu ve ana süreç başlatıldığında bir değişiklik önemli değil ...
Eric Hodonsky

0

Komut dosyanız için bunun yerine Zsh kullanın.

AFAICT, Zsh bu sinir bozucu davranışı sergilemiyor.


Bu, # 473'ün bash yerine Zsh'ı tercih etmesidir. Yakın zamanda, 10 metreyi çalıştıran eski bir bash betiği üzerinde çalışıyorum ve tamamlanmasını beklerken onu düzenleyemiyorum!
Micah Elliott

-5

genellikle, komut dosyanızı çalışırken düzenlemek nadirdir. Yapmanız gereken tek şey, operasyonlarınız için kontrol kontrolü sağlamaktır. Koşulları kontrol etmek için if / else ifadelerini kullanın. Bir şey başarısız olursa, bunu yapın, aksi takdirde yapın. Gitmenin yolu bu.


Aslında, başarısız olan betiklerle ilgili, işlemin ortasında toplu işi değiştirmeye karar vermekten daha azdır. IE, derlemek istediğim daha çok şey olduğunu veya zaten kuyrukta olan belirli işlere ihtiyacım olmadığını fark ediyor.
ack

1
Eğer sıkı olursa ekleme komut, daha sonra bash yapacak beklediğiniz!
Erik Aronesty
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.