Aşağıdaki gibi bir şey oldukça basit bir komut dosyası var:
#!/bin/bash
VAR1="$1"
MOREF='Sudo run command against $VAR1 | grep name | cut -c7-'
echo $MOREF
Bu betiği komut satırından çalıştırdığımda ve argümanları ilettiğimde herhangi bir çıktı alamıyorum. Ancak, $MOREF
değişkeni içindeki komutları çalıştırdığımda çıktı alabiliyorum.
Bir komut dosyasında çalıştırılması gereken bir komutun sonuçlarını nasıl alabilir, bir değişkene kaydedebilir ve daha sonra bu değişkeni ekranda gösterebilir?
Geri tepmelere (`command`
) ek olarak, okumasını daha kolay bulduğum ve yerleştirmeye izin verdiğim $(command)
işlevini kullanabilirsiniz.
OUTPUT="$(ls -1)"
echo "${OUTPUT}"
MULTILINE=$(ls \
-1)
echo "${MULTILINE}"
Tırnak işareti ("
) çok satırlı değerleri korumak için önemlidir.
Doğru yolu
$(Sudo run command)
Kesme işareti kullanacaksanız, `
yerine '
gerekir. Bu karakter "backticks" (veya "Grave accent") olarak adlandırılır.
Bunun gibi:
#!/bin/bash
VAR1="$1"
VAR2="$2"
MOREF=`Sudo run command against "$VAR1" | grep name | cut -c7-`
echo "$MOREF"
Size daha önce de belirttikleri gibi, 'backticks' kullanmalısınız.
Önerilen alternatif $(command)
işlevi de çalışır ve okunması da kolaydır, ancak bunun yalnızca Bash veya KornShell (ve bunlardan türetilen kabukları) ile geçerli olduğunu unutmayın, bu nedenle komut dosyalarınızın çeşitli Unix sistemlerinde gerçekten taşınabilir olması gerekiyorsa, eski backticks gösterimini tercih et.
2nd Edit 2018-02-12: Farklı bir yol ekleyerek, bunun altında uzun süre çalışan görevler için arama yapın!
2018-01-25 Düzenleme: örnek işlevi ekleme (disk kullanımıyla ilgili değişkenleri doldurmak için)
myPi=`echo '4*a(1)' | bc -l`
echo $myPi
3.14159265358979323844
Yuvalama ağırlaşabileceği için parantez uygulandı.
myPi=$(bc -l <<<'4*a(1)')
İç içe örnek:
SysStarted=$(date -d "$(ps ho lstart 1)" +%s)
echo $SysStarted
1480656334
df -k /
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/dm-0 999320 529020 401488 57% /
Sadece istersem Kullanılmış değer:
array=($(df -k /))
array değişkenini görebilirsiniz:
declare -p array
declare -a array='([0]="Filesystem" [1]="1K-blocks" [2]="Used" [3]="Available" [
4]="Use%" [5]="Mounted" [6]="on" [7]="/dev/dm-0" [8]="999320" [9]="529020" [10]=
"401488" [11]="57%" [12]="/")'
Sonra:
echo ${array[9]}
529020
Ama bunu tercih ederim:
{ read foo ; read filesystem size used avail prct mountpoint ; } < <(df -k /)
echo $used
529020
1. read foo
sadece atlayacaktır başlık satırı (değişken $foo
Filesystem 1K-blocks Used Available Use% Mounted on
gibi bir şey içerecektir)
#!/bin/bash
declare free=0 total=0 used=0
getDiskStat() {
local foo
{
read foo
read foo total used free foo
} < <(
df -k ${1:-/}
)
}
getDiskStat $1
echo $total $used $free
Bilginize: declare
satırı gerekli değildir, sadece okunabilirlik için.
Sudo cmd | grep ... | cut ...
hakkındaShell=$(cat /etc/passwd | grep $USER | cut -d : -f 7)
echo $Shell
/bin/bash
(Lütfen faydasız cat
'dan kaçının! Yani bu sadece 1 çatal daha az:
Shell=$(grep $USER </etc/passwd | cut -d : -f 7)
Tüm borular (|
) çatalları ifade eder. Başka bir işlemin yürütülmesi gereken yerlerde, diske erişme, kütüphaneler çağırır vb.
Bu nedenle, örnek için sed
kullanmak, alt işlemi yalnızca bir fork ile sınırlandırır:
Shell=$(sed </etc/passwd "s/^$USER:.*://p;d")
echo $Shell
Ancak çoğu eylemde, çoğunlukla küçük dosyalarda, bash işi kendisi yapabilir:
while IFS=: read -a line ; do
[ "$line" = "$USER" ] && Shell=${line[6]}
done </etc/passwd
echo $Shell
/bin/bash
veya
while IFS=: read loginname encpass uid gid fullname home Shell;do
[ "$loginname" = "$USER" ] && break
done </etc/passwd
echo $Shell $loginname ...
Cevabımı inceleyin Bash'deki bir sınırlayıcıdaki dizgiyi nasıl bölerim?
2. Düzenleme 2018-02-12:Gibi çoklu çatalları önlemek için
myPi=$(bc -l <<<'4*a(1)'
myRay=12
myCirc=$(bc -l <<<" 2 * $myPi * $myRay ")
veya
myStarted=$(date -d "$(ps ho lstart 1)" +%s)
mySessStart=$(date -d "$(ps ho lstart $$)" +%s)
Bu iyi çalışıyor, ancak birçok çatal çalıştırmak ağır ve yavaştır.
ve date
ve bc
gibi komutlar birçok işlem yapabilir, satır satır !!
Görmek:
bc -l <<<$'3*4\n5*6'
12
30
date -f - +%s < <(ps ho lstart 1 $$)
1516030449
1517853288
Bu nedenle, her bir istek için yeni bir çatal başlatmak zorunda kalmadan birçok iş yapmak için long running background işlemini kullanabiliriz.
Bunu düzgün bir şekilde yapmak için bazı dosya tanımlayıcılarına ve fifos ihtiyacımız var:
mkfifo /tmp/myFifoForBc
exec 5> >(bc -l >/tmp/myFifoForBc)
exec 6</tmp/myFifoForBc
rm /tmp/myFifoForBc
(elbette, FD 5
ve 6
kullanılmamış olması gerekir!) ... Oradan, şu işlemi kullanarak kullanabilirsiniz:
echo "3*4" >&5
read -u 6 foo
echo $foo
12
echo >&5 "pi=4*a(1)"
echo >&5 "2*pi*12"
read -u 6 foo
echo $foo
75.39822368615503772256
newConnector
newConnector
işlevimi GitHub.Com veya kendi sitemde bulabilirsiniz (github'da Nota, sitemde iki dosya var, işlev ve demo için kaynaklanabilecek 1 dosyada paketlenmiş) kullanın veya sadece demo için çalıştırın)
Numune:
. Shell_connector.sh
tty
/dev/pts/20
ps --tty pts/20 fw
PID TTY STAT TIME COMMAND
29019 pts/20 Ss 0:00 bash
30745 pts/20 R+ 0:00 \_ ps --tty pts/20 fw
newConnector /usr/bin/bc "-l" '3*4' 12
ps --tty pts/20 fw
PID TTY STAT TIME COMMAND
29019 pts/20 Ss 0:00 bash
30944 pts/20 S 0:00 \_ /usr/bin/bc -l
30952 pts/20 R+ 0:00 \_ ps --tty pts/20 fw
declare -p PI
bash: declare: PI: not found
myBc '4*a(1)' PI
declare -p PI
declare -- PI="3.14159265358979323844"
myBc
işlevi, arka plan görevini basit sözdizimiyle ve tarih için kullanmanıza izin verir:
newConnector /bin/date '-f - +%s' @0 0
myDate '2000-01-01'
946681200
myDate "$(ps ho lstart 1)" boottime
myDate now now ; read utm idl </proc/uptime
myBc "$now-$boottime" uptime
printf "%s\n" ${utm%%.*} $uptime
42134906
42134906
ps --tty pts/20 fw
PID TTY STAT TIME COMMAND
29019 pts/20 Ss 0:00 bash
30944 pts/20 S 0:00 \_ /usr/bin/bc -l
32615 pts/20 S 0:00 \_ /bin/date -f - +%s
3162 pts/20 R+ 0:00 \_ ps --tty pts/20 fw
Buradan, arka plan işlemlerinden birini bitirmek istiyorsanız, onun fd işlevini kapatmanız yeterlidir:
eval "exec $DATEOUT>&-"
eval "exec $DATEIN>&-"
ps --tty pts/20 fw
PID TTY STAT TIME COMMAND
4936 pts/20 Ss 0:00 bash
5256 pts/20 S 0:00 \_ /usr/bin/bc -l
6358 pts/20 R+ 0:00 \_ ps --tty pts/20 fw
bu gerekli değildir, çünkü ana işlem bittiğinde hepsi kapanır.
Yapmanın üç yolunu biliyorum:
1) İşlevler bu tür görevler için uygundur:
func (){
ls -l
}
func
diyerek onu çağır
2) Başka bir uygun çözüm de olabilir:
var="ls -l"
eval $var
3) Üçüncüsü doğrudan değişkenleri kullanıyor:
var=$(ls -l)
OR
var=`ls -l`
Üçüncü çözümün çıktısını iyi bir şekilde elde edebilirsiniz:
echo "$var"
ve ayrıca pis bir şekilde:
echo $var
Sadece farklı olmak için:
MOREF=$(Sudo run command against $VAR1 | grep name | cut -c7-)
Çok satırlı/çoklu komut/s ile yapmak istiyorsanız o zaman bunu yapabilirsiniz:
output=$( bash <<EOF
#multiline/multiple command/s
EOF
)
Veya:
output=$(
#multiline/multiple command/s
)
Örnek:
#!/bin/bash
output="$( bash <<EOF
echo first
echo second
echo third
EOF
)"
echo "$output"
Çıktı:
first
second
third
heredoc komutunu kullanarak, uzun tek satırlı kodunuzu çok satırlı koddan ayırarak işleri kolayca basitleştirebilirsiniz. Başka bir örnek:
output="$( ssh -p $port [email protected]$domain <<EOF
#breakdown your long ssh command into multiline here.
EOF
)"
Bir değişkeni ayarlarken NO - - ve/veya sonra - işaretlerinden sonra olduğundan emin olun. Kelimenin tam anlamıyla bunu anlamaya çalışarak bir saat harcadı, her türlü çözümü denedi! Bu hoş değil.
Doğru:
WTFF=`echo "stuff"`
echo "Example: $WTFF"
Başarısız Olacak hatayla: (malzeme: bulunamadı veya benzeri değil)
WTFF= `echo "stuff"`
echo "Example: $WTFF"
Ya da kullanmanız gerekir
$(command-here)
veya
`command-here`
örnek
#!/bin/bash
VAR1="$1"
VAR2="$2"
MOREF="$(Sudo run command against "$VAR1" | grep name | cut -c7-)"
echo "$MOREF"
Bu, oluşturduğunuz her karmaşık kodu doğru şekilde vurgulayamayan bazı metin editörleriyle birlikte kullanmak için iyi bir yoldur.
read -r -d '' str < <(cat somefile.txt)
echo "${#str}"
echo "$str"
Geri keneleri (aksan mezarları olarak da bilinir) veya $()
kullanabilirsiniz. Gibi
OUTPUT=$(x+2);
OUTPUT=`x+2`;
Her ikisi de aynı etkiye sahiptir. Ancak OUTPUT = $ (x + 2) daha okunaklı ve en yenisidir.
Bazıları bunu faydalı bulabilir. Hilenin $(())
çift köşeli parantez kullandığı değişken yerine tamsayı değerleri:
N=3
M=3
COUNT=$N-1
ARR[0]=3
ARR[1]=2
ARR[2]=4
ARR[3]=1
while (( COUNT < ${#ARR[@]} ))
do
ARR[$COUNT]=$((ARR[COUNT]*M))
(( COUNT=$COUNT+$N ))
done
İşte iki yol daha:
Lütfen boşluğun bash içinde çok önemli olduğunu unutmayın. Bu nedenle, komutunuzun çalışmasını istiyorsanız, daha fazla boşluk bırakmadan olduğu gibi kullanın.
aşağıdaki L harshil atar ve sonra yazdırır
L=$"harshil"
echo "$L"
aşağıdaki, tr
komutunun çıktısını L2'ye atar. tr
, başka bir L1 değişkeninde çalıştırılıyor.
L2=$(echo "$L1" | tr [:upper:] [:lower:])
Çalıştırmaya çalıştığınız komut başarısız olursa, çıktıyı hata akışına yazar ve ardından konsola yazdırılır. Bunu önlemek için, hata akışını yönlendirmeniz gerekir
result=$(ls -l something_that_does_not_exist 2>&1)