Bash komut çalıştırıldıktan sonra nasıl çalışır durumda tutulur?


29

Böyle bir şey çalıştırmak istiyorum:

bash -c "some_program with its arguments"

fakat etkileşimli bir bash elde etmek için bittikten sonra koşmaya devam edin some_program.

Eminim seys -ckadar iyi bir yol değildir man bash:

Etkileşimli bir kabuk, seçenek olmayan argümanlar olmadan ve -c seçeneği olmadan başlatılanlardan biridir.

Peki bu nasıl?

Ana amaç burada açıklanmaktadır .

NOT

  • some_programZaman zaman sonlandırmam gerekiyor
  • Arka plana koymak istemiyorum
  • bashO zaman başka bir şey yapmak için kalmak istiyorum
  • Programı tekrar çalıştırabilmek istiyorum

1
Eğer amaç bu karmaşıksa, burada da açıklamanız gerekir. ama bu sadece bir tavsiye
Kiwy

1
Burada olabildiğince kısa ve çok kesin bir şekilde tarif etmeye çalıştım. Ancak çoğu insanın detaylara odaklanmayacağını ve başka bir şey teklif etmeye çalışacağını beklemiyordum. Açıklığa kavuşturmak için bazı notlar koyacağım.
pawel7318

Bu diğer soruda kaçan terminal ne için? Tanımladığınız hedef yapılabilir, ancak giriş / çıkış işlemlerini gerektirecektir. Ortalama alt kabuğunuz normal bir dosyadan kaçan g / ç terminalini kolayca işlemeyecektir. Sen içine bakmak gerekirpty.
mikeserv

Bu arada benim cevabımdaki tek nedeni terminali çalmam. Sonunda, yine de, ana süreç geri almak için muhtemeldir - ve sonra 4 kb tamponlara bakıyorsunuz.
mikeserv

Neden arka planda bir program koymak istemiyorsunuz? Arka planda başlayın, biraz bash yapın, ön plana çıkarınfg
Bernhard

Yanıtlar:


8
( exec sh -i 3<<SCRIPT 4<&0 <&3                                        
    echo "do this thing"
    echo "do that thing"
  exec  3>&- <&4
  SCRIPT
)

Bu, bir betikten daha iyi yapılır ancak exec $0.Veya bu dosya tanımlayıcılardan biri şu anda kullanılmayan bir terminal aygıtına yönlendirirse, bunun yardımcı olacağını - hatırlamanız gerekir, diğer işlemleri de bu terminali kontrol etmek ister.

Ve bu arada, amacınız, sandığım gibi, senaryoyu gerçekleştirdikten sonra betiğin ortamını korumak, muhtemelen daha iyi hizmet edersiniz:

. ./script

Kabuk en .dotve bash's sourcedeğil bir ve aynıdır - kabuk en .dotişte bu olacak bir garanti hiçbir şekilde olsa, POSIX özel kabuk yerleşiğini olarak belirtilen ve yakın olarak alabilirsiniz garanti olmanın nedenle ...

Her ne kadar yukarıdaki gibi küçük bir sorun ile beklediğiniz gibi yapmalı. Örneğin, şunları yapabilirsiniz:

 ( exec sh -i 3<<SCRIPT 4<&0 <&3                                        
    echo "do this thing"
    echo "do that thing"
    $(cat /path/to/script)
    exec  3>&- <&4
    SCRIPT
 )

Kabuk, betiğinizi çalıştıracak ve etkileşimli bilgi istemine geri döndürecektir - exitkabuğunu betiğinizden, yani işleminizi arka plandan çıkarmaktan kaçındığınız sürece - g / Ç’nizi/dev/null.

DEMO:

% printf 'echo "%s"\n' "These lines will print out as echo" \
    "statements run from my interactive shell." \
    "This will occur before I'm given the prompt." >|/tmp/script
% ( exec sh -i 3<<SCRIPT 4<&0 <&3
    echo "do this thing"
    echo "do that thing"
    $(cat /tmp/script)
    exec  3>&- <&4
SCRIPT
)
sh-4.3$ echo "do this thing"
    do this thing
sh-4.3$ echo "do that thing"
    do that thing
sh-4.3$ echo "These lines will print out as echo"
    These lines will print out as echo
sh-4.3$ echo "statements run from my interactive shell."
    statements run from my interactive shell.
sh-4.3$ echo "This will occur before I'm given the prompt."
    This will occur before I'm given the prompt.
sh-4.3$ exec  3>&- <&4
sh-4.3$

bİRÇOK JOBS

Benim düşüncem, kabuğun yerleşik görev yönetimi seçeneklerini biraz daha yakından tanımanız gerektiğidir. @Kiwy ve @jillagre, cevaplarında bu konuya zaten değindi, ancak daha fazla ayrıntıyı garanti ediyor olabilir. Ve ben zaten yerleşik bir POSIX belirtilen özel kabuk söz ettik ama set, jobs, fg,ve bgbaşka cevap gösterdiği gibi, birkaç tane daha, ve trapvekill daha hala iki.

Eşzamanlı olarak çalışan arka planlı işlemlerin durumu hakkında zaten anında bildirim almıyorsanız, geçerli kabuk seçenekleriniz POSIX tarafından belirtilen varsayılan değerine ayarlanmış olduğundan -m, ancak set -bbunun yerine zaman uyumsuz olarak alabilirsiniz :

% man set
    b This option shall be supported if the implementation supports the
         User  Portability  Utilities  option. It shall cause the shell to
         notify the user asynchronously of background job completions. The
         following message is written to standard error:
             "[%d]%c %s%s\n", <job-number>, <current>, <status>, <job-name>

         where the fields shall be as follows:

         <current> The  character  '+' identifies the job that would be
                     used as a default for the fg or  bg  utilities;  this
                     job  can  also  be specified using the job_id "%+" or
                     "%%".  The character  '−'  identifies  the  job  that
                     would  become  the default if the current default job
                     were to exit; this job can also  be  specified  using
                     the  job_id  "%−".   For  other jobs, this field is a
                     <space>.  At most one job can be identified with  '+'
                     and  at  most one job can be identified with '−'.  If
                     there is any suspended  job,  then  the  current  job
                     shall  be  a suspended job. If there are at least two
                     suspended jobs, then the previous job also shall be a
   m  This option shall be supported if the implementation supports the
         User Portability Utilities option. All jobs shall be run in their
         own  process groups. Immediately before the shell issues a prompt
         after completion of the background job, a message  reporting  the
         exit  status  of  the background job shall be written to standard
         error. If a foreground job stops, the shell shall write a message
         to  standard  error to that effect, formatted as described by the
         jobs utility. In addition, if a job  changes  status  other  than
         exiting  (for  example,  if  it  stops  for input or output or is
         stopped by a SIGSTOP signal), the shell  shall  write  a  similar
         message immediately prior to writing the next prompt. This option
         is enabled by default for interactive shells.

Unix tabanlı sistemlerin çok temel bir özelliği, kullanım yöntemidir signals. Bir zamanlar bu süreci Douglas Adams'ın gezegen tanımına benzeyen konu üzerine aydınlatıcı bir makale okudum.

"Otostopçunun Galaksi Rehberinde, Douglas Adams, bir sürü depresif insanın yaşadığı ve sıkıcı bir şekilde ısırırken, insanlarla iletişim kuran keskin dişleri olan belirli bir hayvan ırkının yaşadığı son derece donuk bir gezegenden bahseder. çekirdeğin kendilerine felç edici veya ölümcül sinyaller göndererek süreçlerle iletişim kurduğu UNIX'e benzer şekilde. Süreçler bazı sinyalleri engelleyebilir ve duruma uyum sağlamaya çalışabilir, ancak çoğu yapmaz. "

Bu atıfta bulunuyor kill signals.

% kill -l 
> HUP INT QUIT ILL TRAP ABRT BUS FPE KILL USR1 SEGV USR2 PIPE ALRM TERM STKFLT CHLD CONT STOP TSTP TTIN TTOU URG XCPU XFSZ VTALRM PROF WINCH POLL PWR SYS

En azından benim için, yukarıdaki alıntı bir çok soruyu yanıtladı. Mesela, her zaman çok garip olduğunu düşündüm ve hiçbir zaman sezgisel değil, bir ddsüreci izlemek istersemkill . Okuduktan sonra mantıklı geldi.

Birçoğunun iyi bir nedenle uyum sağlamaya çalışmadığını söyleyebilirim - geliştiricilerin sizin için önemli olabileceğini düşündüğü herhangi bir bilgi ile terminalinize spam göndermenin bir nimet olacağından çok daha büyük bir sıkıntı olabilir. .

Terminal yapılandırmasına bağlı olarak (siz ile kontrol edebilirsiniz ki stty -a) , CTRL+Zbir ileri muhtemel kümesidir SIGTSTPolasılıkla kabuk geçerli öncelikli süreç grubu lideri olan ve hangi zamanda varsayılan olarak yapılandırılmalıdır trapo sinyali ve son komutu askıya. Yine, jillagre ve @Kiwy'nin cevaplarının birlikte gösterdiği gibi, bu işlevselliği istediğiniz gibi uyarlamanıza engel olmanıza gerek yok.

SCREEN JOBS

Bu özelliklerden yararlanmak için önce onları anlamanız ve işlemlerini kendi ihtiyaçlarınıza göre özelleştirmeniz beklenir. Örneğin, şu screenrc'i Github'da şu screenanahtar teslimlerini içeren buldum SIGTSTP:

# hitting 'C-z C-z' will run Ctrl+Z (SIGTSTP, suspend as usual)
bind ^Z stuff ^Z

# hitting 'C-z z' will suspend the screen client
bind z suspend

Bu, bir çocuk screensüreci olarak çalışan bir süreci ya da screençocuk sürecini istediğiniz gibi askıya almayı basit bir mesele haline getirir .

Ve hemen sonra:

% fg  

VEYA:

% bg

İstediğiniz gibi işlemi ön plana çıkarır veya arkaplan eder. jobsYerleşik herhangi bir zamanda size bunların bir listesini sağlayabilir. Operand'ı eklemek, -lpid detaylarını içerecektir.


Çok ilginç görünüyor. Hepsini daha sonra bugün test edebileceğim.
pawel7318

23

İstediğinizi gerçekleştiren, ancak sorunu ve bash'ın nasıl çalıştığını anlamadığınız sürece bir anlam ifade etmeyebilecek daha kısa bir çözüm:

bash -i <<< 'some_program with its arguments; exec </dev/tty'

Bu bir bash kabuğunu başlatacak, başlayacak some_programve çıktıktan sonra some_programbir bash kabuğuna bırakılacaksınız.

Temelde yaptığımız şey, STDIN üzerindeki bir ipi beslemek. Bu dize some_program with its arguments; exec </dev/tty. Bu, bash'a önce başlamasını some_programve sonra koşmasını söyler exec </dev/tty. Bu yüzden onu ilettiğimiz dizgiden komutları okumaya devam etmek yerine, bash okumaya başlayacaktır /dev/tty.

-iBash başlatıldığında, bu STDIN bir tty olup olmadığını kontrol eder, çünkü, ve başlatıldığında değil. Ama sonra olacak, bu yüzden etkileşimli moda zorlayacağız.


Başka bir çözüm

Bunun çok taşınabilir olabileceğini düşündüğüm bir diğer fikir de, ~/.bashrcdosyanızı sonuna kadar eklemek .

if [[ -n "START_COMMAND" ]]; then
  start_command="$START_COMMAND"
  unset START_COMMAND
  eval "$start_command"
fi

Ardından, ilk önce bir komutu olan bir kabuk başlatmak istediğinizde, sadece şunu yapın:

START_COMMAND='some_program with its arguments' bash

Açıklama:

Bunun birçoğunun açık olması gerekir, ancak değişken ismi değiştiren değişken için reson, değişkeni yerelleştirebilmemiz içindir. Yana $START_COMMANDbir ihraç değişkendir, bu kabuğun herhangi çocuklar tarafından miras olacak ve başka Bash kabuk çocuklardan biriyse, yine komutunu çalıştırın edeceğiz. Bu yüzden değeri yeni bir desteklenmeyen değişkene ( $start_command) atar ve eskisini sileriz .


Birden fazla ne varsa, havaya uçurmak? Bir emir? hayır, hala çalışmalıyım. Ancak taşınabilirlik konusunda haklısın. Orada 2 faktör var, <<<POSIX değil, ama echo "string here" | bash -ibunun yerine. Sonra /dev/ttybir linux şey var. Ama FD'yi basmadan önce FD'yi değiştirebilir ve sonra yaptığınız gibi görünen STDIN'i yeniden açabilirsiniz, ancak işleri basit tutmayı seçtim.
Patrick

Tamam, sadece kavga etme. Bu sadece benim için çalışıyor ve ihtiyacım olan her şeyi yapıyor. POSIX ve taşınabilirlik hakkında pek fazla umrumda değil, kutumda ve sadece orada ihtiyacım var. Mikeserv'in cevabını da kontrol edeceğim ama bunu şimdi yapamam.
pawel7318

1
Kavga etmiyorum :-). Mikserv'in cevabına saygı duyuyorum. Uyumluluk için gitti, sadelik için gittim. Her ikisi de tamamen geçerlidir. Aşırı karmaşık değilse bazen uyumluluk için giderim. Bu durumda buna değeceğini düşünmedim.
Patrick

2
@Patrick, /dev/ttybir Linux şey değil, kesinlikle POSIX.
jlliagre


8

Bu hile yapmak gerekir:

bash -c "some_program with its arguments;bash"

Düzenle:

Güncellemenizi takiben yeni bir deneme:

bash -c "
trap 'select wtd in bash restart exit; do [ \$wtd = restart ] && break || \$wtd ; done' 2
while true; do
    some_program with its arguments
done
"
  • Zaman zaman some_program'ı sonlandırmam gerekiyor

Kullan ControlC, bu küçük menü size sunulacak:

1) bash
2) restart
3) exit
  • Arka plana koymak istemiyorum

Durum böyle.

  • Ben bash üstünde kalmak sonra başka bir şey yapmak istiyorum

"Bash" seçimini yap

  • Programı tekrar çalıştırabilmek istiyorum

"Yeniden başlat" seçimini yap


fena değil fena değil .. ama son komuta geri dönebilmek için de iyi olurdu. Bunun için bir fikrin var mı? Benim başka bir soru kontrol edin burada ben ihtiyaç için ne görmek. Belki başka bir yaklaşım önerirsin
pawel7318

Bu bir alt kabuk yürütür. Sanırım asker senaryo ortamını korumaya çalışıyor.
mikeserv

teşekkür ederim jlliagre - güzel girişim ama benim için çok yararlı değil. Genellikle ctrl + C tuşlarına basarım ve sadece yapması gerekeni yapmasını bekliyorum. Ek menü sadece çok fazla.
pawel7318

@ pawel7318 davranışı, CTRL+Cterminalinizin varsayılan yapılandırmasının a olarak yorumlanması için yalnızca bir yan etkisidir SIGINT. Bunu istediğiniz gibi değiştirebilirsiniz stty.
mikeserv

@ pawel7318 daha açıklamak için, SIGINTbir trappedyukarıda 2.
mikeserv

3

Komut dosyanızı bir başlangıç ​​dosyası olarak geçirerek yapabilirsiniz:

bash --init-file foo.script

Veya komut satırından iletebilirsiniz:

bash --init-file <(echo "ls -al")

Bunun --init-file, sistem genelinde başlatma dosyalarını okumak için olduğunu , /etc/bash.bashrcbu nedenle bunları sourcekomut dosyasında ' ' isteyebilirsiniz .


0

Bunu yapmanın amacını gerçekten görmüyorum, çünkü zaten bu programı çalıştırdıktan sonra bir kabuğa geri döndünüz. Ancak, bunu yapabilirsiniz:

bash -c "some_program with its arguments; bash"

Bu program çalıştıktan sonra etkileşimli bir bash başlatacak.


Bu bir denizaltı başlattı.
mikeserv

0

Geçerli bash açık tutmak için komutu arka planda koyabilirsiniz:

some_program with its arguments &

Çalışmaya geri dönmek için fgkomutu daha sonra ^+ztekrar kullanabilirsiniz.


bu sefer değil. Bu bash'ı çalıştırmak istediğimi düşünüyorsun ... durum böyle değil.
pawel7318

@ pawel7318 biraz daha fazla açıklarsanız size belki daha iyi bir cevap verebiliriz?
Kiwy

Lütfen burada başka bir soruma bakın .
pawel7318

@ pawel7318 Eğer sorunuzla ilgiliyseniz, lütfen kendi sorunuzdaki diğer soruya bağlantıyı ekleyin.
Kiwy

1
@ pawel7318 bash ya da değil, eğer süreç arka planını kaldıramazsa, bana çok yabancı bir kabuk kullanıyorsunuz. Ve Kiwi ile aynı fikirdeyim - eğer sorunuz varsa bu bilgi size daha iyi hizmet ederdi.
mikeserv

0

Komutu çalıştırmak için ekranı kullanmak isteyebilirsiniz. Komut tamamlandıktan sonra oturuma yeniden ekleyebilirsiniz.

Alternatif olarak, sadece komutu arka planda çalıştırın some_program with its arguments&. Bu, komutu yeniden çalıştırma ve bir kez yapıldığında komutun durumunu alma becerisini bırakacaktır.


Tam olarak çalıştırıyorum screenama arka plana koymak benim için kullanışlı değil - bazen programı sonlandırmam, başka bir şey yapmam ve tekrar çalıştırmam gerekebilir. Ve asıl amaç bu hızlı yapmaktır.
pawel7318

@ pawel7318 Arka plan programını kill %veya komutuyla öldürebilirsiniz kill %1.
BillThor
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.