Ssh üzerinde bir komutta true ile ORing


15

pkill -fSsh ile uzaktan çalıştırmayı denediğimde ve olası hata kodunu atmaya çalıştığımda (hiçbir işlem bulunmasa bile komut dosyamın geri kalanıyla devam etmek için) || truebeklediğim gibi davranmıyor.

$ pkill asdf || true
$ echo $?
0
$ pkill -f asdf || true
$ echo $?
0
$ ssh pi@10.20.0.10 "pkill asdf || true"
$ echo $?
0
$ ssh pi@10.20.0.10 "pkill -f asdf || true"
255

Ben 255 döndürür ssh olduğunu varsayalım, tırnak arasındaki komutu değil, ama neden?

Yanıtlar:


29

Sizin varsayım temiz olmadığını sshkendisini döndürdüğü 255 çıkış durumu doğrudur. sshAdam sayfa belirtiyor:

ssh uzak komutun çıkış durumuyla veya bir hata oluşursa 255 ile çıkar.

Basitçe çalışacak ssh pi@10.20.0.10 "pkill -f asdf"olsaydınız, büyük olasılıkla " Eşleşen işlem yok " durumuna 1karşılık gelen bir çıkış durumu alırsınız .pkill

Zorlayıcı kısım, çalıştırdığınızda SSH ile neden bir hata oluştuğunu anlamaktır

ssh pi@10.20.0.10 "pkill -f asdf || true"

SSH uzaktan komutları

SSH sunucusu uzak komut (lar) ı çalıştırmak için bir kabuk başlatır. İşte bunun bir örneği:

$ ssh server "ps -elf | tail -5"
4 S root     35323  1024 12  80   0 - 43170 poll_s 12:01 ?        00:00:00 sshd: anthony [priv]
5 S anthony  35329 35323  0  80   0 - 43170 poll_s 12:01 ?        00:00:00 sshd: anthony@notty
0 S anthony  35330 35329  0  80   0 - 28283 do_wai 12:01 ?        00:00:00 bash -c ps -elf | tail -5
0 R anthony  35341 35330  0  80   0 - 40340 -      12:01 ?        00:00:00 ps -elf
0 S anthony  35342 35330  0  80   0 - 26985 pipe_w 12:01 ?        00:00:00 tail -5

Not varsayılan kabuk olduğu bashve uzaktan komut, basit bir komutu ve bir olmadığını boru hattı , “bir ya da daha fazla, komutlar dizisi kontrol operatörü tarafından ayrılmış |”.

Bash kabuğu, -cseçenek tarafından kendisine iletilen komut basit bir komutsa , aslında yeni bir işlem istemeyerek optimize edebileceğini, yani execekstra adımdan geçmek yerine doğrudan basit komut olduğunu anlayacak kadar zekidir. arasında forkdaha önce ing execs. Uzaktan basit bir komutu çalıştırdığınızda neler olduğuna bir örnek ( ps -elfbu durumda):

$ ssh server "ps -elf" | tail -5
1 S root     34740     2  0  80   0 -     0 worker 11:49 ?        00:00:00 [kworker/0:1]
1 S root     34762     2  0  80   0 -     0 worker 11:50 ?        00:00:00 [kworker/0:3]
4 S root     34824  1024 31  80   0 - 43170 poll_s 11:51 ?        00:00:00 sshd: anthony [priv]
5 S anthony  34829 34824  0  80   0 - 43170 poll_s 11:51 ?        00:00:00 sshd: anthony@notty
0 R anthony  34830 34829  0  80   0 - 40340 -      11:51 ?        00:00:00 ps -elf

Daha önce bu davranışla karşılaştım ama bu AskUbuntu yanıtı dışında daha iyi bir referans bulamadık .

pkill davranışı

Yana pkill -f asdf || truebasit bir komut (bir var olmayan komut listesi ) çalıştırdığınızda, yukarıdaki optimizasyon böylece oluşamaz ssh pi@10.20.0.10 "pkill -f asdf || true", sshdsüreç çatal ve execs bash -c "pkill -f asdf || true".

Ctx'in cevabının işaret pkillettiği gibi, kendi sürecini öldürmeyecek. Ancak, olacak olan komut satırı ile eşleşen başka öldürme işlemi -fdesen. bash -cKendi ebeveyn (tesadüfen de) - bu bu süreci öldürür böylece komut bu kalıbı ile eşleşir.

SSH sunucusu daha sonra uzak komutları çalıştırmak için başlattığı kabuk işleminin beklenmedik bir şekilde öldürüldüğünü görür, böylece SSH istemcisine bir hata bildirir.


1
Cevap doğru olduğu gibi bir sorun kaynağını tanımlar iken pkillonun arg liste Regexp'i eşleştiği için üst kabuk sürecini öldürür, bir terminoloji itiraz edeceğiz: x || yolduğu değil bir bileşik komutu , şey komut listesi .
Stéphane Chazelas

@ StéphaneChazelas Geri bildiriminiz için teşekkür ederiz. Bash'in koşullu yapıları bileşik komutlar olarak dahil etmesiyle devam ediyordum ama x||ybir komut listesi olarak düşünmenin daha mantıklı olduğunu kabul ediyorum . Şimdi cevabımı çeşitli POSIX tanımlarına bağlantılar içerecek şekilde düzenledim.
Anthony Geoghegan

1
Genel durumda, optimize edemeyeceği kadar çok şey olmadığını unutmayın, çünkü bir komut listesi , eşiğin çalışacağı başka bir komutu olduğunu (potansiyel olarak). Gelen zsh/ ksh93/ FreeBSD sh, false || pkill -f asdfolurdu pkillkabuk işlemi yürütülür. bashoptimizasyonu yalnızca tek bir basit komut olduğunda yapar. true; pkill -f asdfbir sorun olurdu.
Stéphane Chazelas

9

Uzaktan komutunuz kendini öldürür:

$ ssh 10.0.3.70 'pgrep -af asdf'
$ ssh 10.0.3.70 'pgrep -af asdf || true'
1018 bash -c pgrep -af asdf || true

pgrep ve pkill kendi süreçlerini görmezden gelir, ancak -f bayrağıyla üst kabuğu bulurlar:

$ pgrep -af asdf
$ pgrep -af asdf || true
$ bash -c 'pgrep -af asdf'
$ bash -c 'pgrep -af asdf || true'
9803 bash -c pgrep -af asdf || true

Mantıklı! bash -c 'pgrep -af asdf'(olmadan || true) yok değil kendisini bulabilirsiniz. Neden olmasın? Var -f.
Gauthier

2
@Gauthier Aslında, bu durumda, Bash komutun basit bir komut olduğunu (bileşik bir komut değil) fark edecek kadar zeki olduğunu, bu yüzden aslında yeni bir süreç çatallayarak optimize eder. Daha önce benzer davranışlarla karşılaştığımı hatırlıyorum (cevabımı güncellemeliyim).
Anthony Geoghegan

3

Pkill'den "asdf" ile eşleşen her şeyi öldürmesini istersiniz. [A] sdf ile eşleşmesini söylemelisiniz, bu şekilde yine de "asdf" adında bir şey arar, ancak kendisini görmez (asdf'yi [a] sdf ile hizalarsanız, s'nin hizalandığına dikkat edin] ve değil.)

ssh 10.0.3.70 'pgrep -af "[a]sdf" || true'

Grep / egrep / awk / etc ile de kullanılan yaygın bir numaradır:

ps -ef | grep "something"  # will sometimes match itself too
ps -ef | grep "[s]omething" # will not match itself

# why it works:
# the commandline contains:     ps -ef | grep [s]omething
# and grep tries to find:                      something

Bu numara eski ve onlarca yıl önce Unix SSS'de gördüm (bu hala iyi bir okuma!)

"Otomatikleştirmek" için kolay değildir, ancak genellikle değişken bir dizge için her seferinde grep gerektiğinde regexp = "bir şey" yapmayı deneyebilirsiniz:

grep "$(echo "${regexp}" | LC_ALL='C' sed -e 's/[a-zA-Z0-9_-]/[&]/')" 
#  if regexp="something",  it does: grep "[s]omething"
#  if regexp="otherthing", it does: grep "[o]therthing"
#  if regexp="^thirdthing", it does: grep "^[t]hirdthing" #ok, kept the "^"
#BUT fails on : regexp="[abc]def", as it does: grep "[[a]bc]def" instead of grep "[abc][d]ef" ...

Not: 'Başarısız' grep örneğimin, regexp'i zaten kendisiyle eşleşmediği için tutabileceğinin farkındayım (a, b veya c komut satırının ']' ile eşleşmeyecek) . Ancak normal ifadenin bir testinin yapılması önemsiz değildir. Genel olarak, hile çalışır. otomatik olan çoğu zaman çalışır. Değilse, bazı akıllı hack'ler (veya manuel müdahale) gerekecektir.
Olivier Dulac

Ayrıca, (abc)?(def)?olmak zorunda kalacak ([a]bc)?([d]ef)?... Yapamazsınız ayrıştırma düzenli ifade ile düzenli ifade ?! > :-)
wizzwizz4

@ wizzwizz4 biliyorum. ancak örnekleminiz zaten kendisiyle eşleşmiyor. Bu karmaşık bir şey, ben sadece daha basit vakalar için basit bir çözüm
sağladım

@ wizzwizz4 Zaten ilk yorumumda bunu söylüyorum ...
Olivier Dulac
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.