Bir değişkenin değeri bir komutun stdinine nasıl aktarılır?


105

Biraz güvenli olması gereken, yani güvenli verileri komut parametreleri üzerinden geçirmeyen ve tercihen geçici dosyalar kullanmayan bir kabuk komut dosyası yazıyorum. Bir değişkeni bir komutun stdinine nasıl aktarabilirim? Ya da mümkün değilse, bu tür görevler için geçici dosyalar nasıl doğru şekilde kullanılır?


Bir saldırgan değişebilir $PATHmi? Bu catdeğiştirilebilir/bin/cat "$@" | tee /attacker/can/read/this/file
12431234123412341234123

Yanıtlar:


74

O kadar basit bir şey:

echo "$blah" | my_cmd

7
Değişkeninizdeki boşluklara dikkat edin: echo "$blah"daha iyidir.
Jonathan Leffler

13
Bakalım nasıl başa çıkacaksın blah=-n, blah=-e... printfonun yerine kullan. unix.stackexchange.com/questions/65803/…
Camilo Martin

1
kırılgan ve hataya açık gibi görünüyor, değil mi?
ThorSummoner

20
6 yıl sonra, bu cevabı silebilseydim yapardım (ama kabul edilmediği için yapamam ...)
Oliver Charlesworth

1
@OliverCharlesworth, neden kullanmak için düzenlemiyorsunuz printf '%s\n' "$blah"? Bu tek bir değişiklikle ( echoStephane'ın mükemmel cevabının Unix ve Linux'ta Neden printfdaha iyidir echo? 'De ayrıntılı olarak girdiği veya şartnamenin UYGULAMA KULLANIMI bölümünün daha kısaca değindiği birçok tuzaktan kaçınarak ) makul cevap. echo
Charles Duffy

195

Bir değeri geçirilmesi stdinde bash olarak basit gibidir:

your-command <<< "$your_variable"

Değişken ifadelerin başına daima tırnak işareti koyduğunuzdan emin olun!

Dikkatli olun, bu muhtemelen sadece içinde çalışacak bashve çalışmayacaktır sh.


39
Bildiğim kadarıyla herestring'in <<<mevcut olması garanti değil, POSIX tabanında değiller. Sadece onları içeri aldığınız sürece beklendiği gibi çalışacaklar bash. Ben sadece bundan bahsediyorum, çünkü OP özellikle 'bash' değil 'kabuk' dediler. Soruyu bashşu şekilde etiketlemesine rağmen ... bu hala kabul edilebilir bir cevap.
JM Becker

Durum böyle olsa da, echobir boru oluşturulması nedeniyle yöntem kullanılırsa hassas bilgilerin daha kolay sızdırılması muhtemeldir . Herestring komutu tamamen tarafından işlenecektir bash, ancak bu durumda (belirtildiği gibi) bashınızda çalışacağını daha iyi bilseniz de, aksi takdirde herestring'i desteklememenin bir sonucu olarak üretilen herhangi bir hata mesajı da söz konusu bilgiyi sızdıracaktır.
Steven Lu

@StevenLu Wait, echoyerleşik bir. Orada boru yok, değil mi? Bu Unix, ama o kadar da Unix olamaz .
Camilo Martin

4
@StevenLu printf '%s\n' "$var"ile aynı sonuçları verir, echo "$var"ancak kırılmaz, örneğin var=-en, ve bash bile gerektirmez.
Camilo Martin

2
Ayrıca buradaki dizeler için dizeye bir satırsonu eklendiğine dikkat edin.
pdr

19

' echo "$var" | commandİşlemlerinin, standart girişin yankılanan hat (lar) la sınırlı olduğu anlamına geldiğini unutmayın . Terminalin de bağlanmasını istiyorsanız, o zaman daha meraklı olmanız gerekir:

{ echo "$var"; cat - ; } | command

( echo "$var"; cat -   ) | command

Bu, ilk satırların içeriğinin olacağı, $varancak geri kalanın catstandart girdinin okunmasından geleceği anlamına gelir . Komut çok süslü bir şey yapmazsa (komut satırı düzenlemesini açmayı deneyin veya vimyaptığı gibi çalıştırın ), o zaman sorun olmayacaktır. Aksi takdirde, gerçekten süslü olmanız gerekir - bence expectveya türevlerinden biri muhtemelen uygun olacaktır.

Komut satırı notasyonları pratik olarak aynıdır - ancak ikinci noktalı virgül, parantezlerle değil, parantezlerle birlikte gereklidir.


( echo "$LIST"; cat - ) | sed 1qbu benim için çalışıyor, ancak bu komut dosyasını çalıştırdığımda ctrl d'ye basmam gerekiyor?
Gert Cuykens

Evet; cat -Eğer yazarak kontrol D EOF anlatmamız gerek yüzden, EOF veya yürütülmesine kadar klavyeden okumaya devam eder.
Jonathan Leffler

EOF'yi aşmanın bir yolu var mı? sed ihtiyaçlar kedi
Gert Cuykens

catİlk satırdaki gibi terminal girişi istemiyorsanız hiç kullanmanıza gerek yoktur. Veya catbir dosyayı listelemek için kullanabilirsiniz . Veya ... Komutun terminal girişini okumasını istiyorsanız, girişin sonuna geldiğinde ona söylemelisiniz. Veya kullanabilirsiniz ( echo "$var"; sed /quit/q - ) | command; bu, siz 'çıkış' içeren bir satır yazana kadar devam eder. Bununla nasıl başa çıkacağınız konusunda sonsuz bir şekilde yaratıcı olabilirsiniz. Kullanıcılar Ekvador ile çalışmaya başladığında çalışmayı bırakan bir programın eski şehir efsanesine dikkat edin. Başkent Quito adını yazarlar ve programdan çıkılır.
Jonathan Leffler

Öyle söylüyorsan tamam. Ama neden sadece değil echo "$LIST" | sed 1q | ...? Her şey ne hakkında olduğuna bağlı. <<EOFNotasyonu dosya aşağı kendi yerden yana bir satırın başında bir EOF gerektirir gerekir. Kullanmazdım sanırım - ama hala neyi başarmaya çalıştığından emin değilim. Basit echo "$LIST" | commandveya echo $LIST | commandpratikte muhtemelen yeterli olacaktır (ve ikisi arasındaki farkın önemini bilmeniz önemlidir).
Jonathan Leffler

16

Martin'in cevabını beğendim, ancak değişkende ne olduğuna bağlı olarak bazı sorunları var. Bu

your-command <<< """$your_variable"""

değişken "veya!"


4
Ama neden? Ayrıca, herhangi bir sorunu yeniden üretemiyorum: foo1=-; foo2='"'; foo3=\!; cat<<<"$foo1"; cat<<<"$foo2"; cat<<<"$foo3"benim için iyi çalışıyor. Üçü tam olarak ne "yapıyor? AFAIK, sadece boş bir dizenin başına ve sonuna ekleme yapıyorsunuz.
phk

Gerçek bir şey dene. Sanki emriniz bir şekilde ssh. ve değişkeniniz bir kabuk betiğidir.
Robert Jacobs

16
(cat <<END
$passwd
END
) | command

catGerçekten gerekli değil, ama daha iyi kod yapılandırılmasına yardımcı olan ve size komutuna girdi olarak parantez içinde daha komutlarını kullanmak için izin verir.


Ancak bu yöntem komutunuza birden çok satır $passwd
geçirmenize

4
Bu şimdiye kadarki en iyi cevaptır ve değişken içerikleri boruya veya gözetleme sürecine sızdırmaz.
user2688272

8

Martin'in cevabına göre, Here Strings adında bir bash özelliği var (bu da daha yaygın olarak desteklenen Here Documents özelliğinin bir çeşididir ).

http://www.gnu.org/software/bash/manual/bashref.html#Here-Strings

3.6.7 Buradaki Dizeler

Buradaki belgelerin bir çeşidi, biçim şu şekildedir:

<<< word

Sözcük genişletilir ve standart girişindeki komuta verilir.

Here Strings'in yalnızca bash için göründüğünü unutmayın, bu nedenle, daha iyi taşınabilirlik için, PoltoS'un cevabına göre orijinal Here Documents özelliği ile muhtemelen daha iyi durumda olursunuz:

( cat <<EOF
$variable
EOF
) | cmd

Veya yukarıdakilerin daha basit bir çeşidi:

(cmd <<EOF
$variable
EOF
)

Bunu diğer komutlara yönlendirmek istemiyorsanız (ve atlayabilirsiniz ).


5

Bu sağlam ve taşınabilir yöntem, yorumlarda zaten göründü. Bağımsız bir cevap olmalı.

printf '%s' "$var" | my_cmd

veya

printf '%s\n' "$var" | my_cmd

Notlar:

  • Bundan daha iyi echo, nedenler burada: Neden daha printfiyi echo?
  • printf "$var"Hata. İlk bağımsız değişken çeşitli diziler gibi biçimi %sya da \nedilir yorumlanır . Değişkeni sağa geçirmek için format olarak yorumlanmamalıdır.
  • Genellikle değişkenler son satırlar içermez. Önceki komut (with %s) değişkeni olduğu gibi geçirir. Ancak metinle çalışan araçlar eksik bir satırı yok sayabilir veya bundan şikayet edebilir (bkz. Metin dosyaları neden yeni satırla bitmeli? ). Dolayısıyla %s\n, değişkenin içeriğine bir satırsonu karakteri ekleyen ikinci komutu (ile ) isteyebilirsiniz . Açık olmayan gerçekler:

    • Burada Bash ( <<<"$var" my_cmd) içindeki dizge bir satırsonu ekler.
    • Bir satırsonu ekleyen herhangi bir yöntem my_cmd, değişken boş veya tanımsız olsa bile boş olmayan stdin ile sonuçlanır .

4

Bunu dene:

echo "$variable" | command

ancak $ değişkeninin içeriği, örneğin ps -uecho çalışırken çıktısında görünmez mi?

2
hayır olmayacak. echoyerleşiktir, bu nedenle
ps'de

2
Değişkeninizdeki boşluklara dikkat edin: echo "$variable"daha iyidir.
Jonathan Leffler

bu doğru, bash çift boşluk yiyecek, daha akıllı kabukları
yemeyecek

-1

Sadece yap:

printf "$my_var" | my_cmd

Değişken boşluk içermiyorsa tırnak işaretleri atlanabilir.
Bash kullanıyorsanız, şunları da yapabilirsiniz:

echo -n "$my_var" | my_cmd

Echo'yu -n olmadan kullanmaktan kaçının çünkü bu, vraiable'ı sonuna bir satır sonu ekleyerek boru haline getirecektir.


1
$ my_var ise çalışmaz %s, printf hiçbir şey yazdırmaz. my_var="%s"; printf "$my_var"; - belki denersin printf "%s" "$my_var" | my_cmd ?
hanshenrik
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.