it-swarm-id.com

Bagaimana cara mengatur variabel ke keluaran dari perintah di Bash?

Saya memiliki skrip yang cukup sederhana yaitu seperti berikut:

#!/bin/bash

VAR1="$1"
MOREF='Sudo run command against $VAR1 | grep name | cut -c7-'

echo $MOREF

Ketika saya menjalankan skrip ini dari baris perintah dan memberikan argumen, saya tidak mendapatkan hasil apa pun. Namun, ketika saya menjalankan perintah yang terkandung dalam variabel $MOREF, saya bisa mendapatkan output.

Bagaimana seseorang dapat mengambil hasil dari perintah yang perlu dijalankan dalam skrip, menyimpannya ke variabel, dan kemudian menampilkan variabel itu di layar?

1317
John

Selain backticks (`command`), Anda dapat menggunakan $(command), yang menurut saya lebih mudah dibaca, dan memungkinkan untuk bersarang.

OUTPUT="$(ls -1)"
echo "${OUTPUT}"

MULTILINE=$(ls \
   -1)
echo "${MULTILINE}"

Mengutip (") penting untuk mempertahankan nilai multi-baris.

1989
Andy Lester

Cara yang benar adalah

$(Sudo run command)

Jika Anda akan menggunakan tanda kutip, Anda perlu `, bukan '. Karakter ini disebut "backticks" (atau "Aksen kubur").

Seperti ini:

#!/bin/bash

VAR1="$1"
VAR2="$2"

MOREF=`Sudo run command against "$VAR1" | grep name | cut -c7-`

echo "$MOREF"
240
Ilya Kogan

Seperti yang telah ditunjukkan kepada Anda, Anda harus menggunakan 'backticks'.

Alternatif yang diusulkan $(command) bekerja dengan baik, dan juga lebih mudah dibaca, tetapi perhatikan bahwa itu hanya valid dengan Bash atau KornShell (dan shell yang berasal dari itu), jadi jika skrip Anda harus benar-benar portabel pada berbagai sistem Unix, Anda harus lebih suka notasi backticks lama.

64
bitwelder

Beberapa bash trik yang saya gunakan untuk mengatur variabel dari perintah

Edit ke-2 2018-02-12: Menambahkan cara berbeda, cari di bagian bawah ini untuk tugas yang sudah berjalan lama!

2018-01-25 Edit: tambahkan fungsi sampel (untuk mengisi vars tentang penggunaan disk)

Pertama cara sederhana dan kompatibel

myPi=`echo '4*a(1)' | bc -l`
echo $myPi 
3.14159265358979323844

Paling kompatibel, cara kedua

Karena sarang dapat menjadi berat, kurung diimplementasikan untuk ini

myPi=$(bc -l <<<'4*a(1)')

Sampel bersarang:

SysStarted=$(date -d "$(ps ho lstart 1)" +%s)
echo $SysStarted 
1480656334

membaca lebih dari satu variabel (dengan bashisme)

df -k /
Filesystem     1K-blocks   Used Available Use% Mounted on
/dev/dm-0         999320 529020    401488  57% /

Jika saya hanya ingin Bekas nilai:

array=($(df -k /))

anda bisa melihat array variabel:

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]="/")'

Kemudian:

echo ${array[9]}
529020

Tapi saya lebih suka ini:

{ read foo ; read filesystem size used avail prct mountpoint ; } < <(df -k /)
echo $used
529020

read foo pertama hanya akan lewati baris header (variabel $foo akan berisi sesuatu seperti Filesystem 1K-blocks Used Available Use% Mounted on)

Fungsi sampel untuk mengisi beberapa variabel:

#!/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

Nota: baris declare tidak diperlukan, hanya untuk keterbacaan.

Tentang Sudo cmd | grep ... | cut ...

Shell=$(cat /etc/passwd | grep $USER | cut -d : -f 7)
echo $Shell
/bin/bash

(Harap hindari cat yang tidak berguna! Jadi ini hanya 1 garpu lebih sedikit:

Shell=$(grep $USER </etc/passwd | cut -d : -f 7)

Semua pipa (|) menyiratkan garpu. Di mana proses lain harus dijalankan, mengakses disk, pustaka panggilan, dan sebagainya.

Jadi menggunakan sed untuk sampel, akan membatasi subproses menjadi hanya satu garpu:

Shell=$(sed </etc/passwd "s/^$USER:.*://p;d")
echo $Shell

Dan dengan bashisms:

Tetapi untuk banyak tindakan, kebanyakan pada file kecil, bash bisa melakukan pekerjaan itu sendiri:

while IFS=: read -a line ; do
    [ "$line" = "$USER" ] && Shell=${line[6]}
  done </etc/passwd
echo $Shell
/bin/bash

atau

while IFS=: read loginname encpass uid gid fullname home Shell;do
    [ "$loginname" = "$USER" ] && break
  done </etc/passwd
echo $Shell $loginname ...

Lebih jauh tentang pemisahan variabel...

Lihat jawaban saya untuk Bagaimana cara membagi string pada pembatas di Bash?

Alternatif: mengurangi garpu dengan menggunakan tugas yang sudah berjalan lama berlatar belakang

Edit ke-2 2018-02-12:Untuk mencegah beberapa fork seperti

myPi=$(bc -l <<<'4*a(1)'
myRay=12
myCirc=$(bc -l <<<" 2 * $myPi * $myRay ")

atau

myStarted=$(date -d "$(ps ho lstart 1)" +%s)
mySessStart=$(date -d "$(ps ho lstart $$)" +%s)

Ini berfungsi dengan baik, tetapi menjalankan banyak garpu berat dan lambat.

dan perintah seperti date dan bc dapat membuat banyak operasi, baris demi baris !!

Lihat:

bc -l <<<$'3*4\n5*6'
12
30

date -f - +%s < <(ps ho lstart 1 $$)
1516030449
1517853288

Jadi kita dapat menggunakan berjalan lama proses latar belakang untuk membuat banyak pekerjaan, tanpa harus memulai yang baru garpu untuk setiap permintaan.

Kami hanya perlu beberapa deskriptor file dan fifos untuk melakukan ini dengan benar:

mkfifo /tmp/myFifoForBc
exec 5> >(bc -l >/tmp/myFifoForBc)
exec 6</tmp/myFifoForBc
rm /tmp/myFifoForBc

(tentu saja, FD 5 dan 6 harus tidak digunakan!) ... Dari sana, Anda dapat menggunakan proses ini dengan:

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

Menjadi fungsi newConnector

Anda dapat menemukan fungsi newConnector saya di GitHub.Com atau di situs saya sendiri (Nota on github, ada dua file, di situs saya, fungsi dan demo dibundel menjadi 1 file yang dapat bersumber dari 1 gunakan atau jalankan saja untuk demo)

Mencicipi:

. 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"

Fungsi myBc memungkinkan Anda menggunakan tugas latar belakang dengan sintaks sederhana, dan untuk tanggal:

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

Dari sana, jika Anda ingin mengakhiri salah satu proses latar belakang, Anda hanya perlu menutup - fd:

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

yang tidak diperlukan, karena semua fd tutup saat proses utama selesai.

59
F. Hauri

Saya tahu tiga cara untuk dilakukan:

1) Fungsi cocok untuk tugas-tugas seperti:

func (){
ls -l
}

Meminta dengan mengatakan func

2) Juga solusi lain yang cocok bisa eval:

var="ls -l"
eval $var

3) Yang ketiga menggunakan variabel secara langsung:

var=$(ls -l)
OR
var=`ls -l`

anda bisa mendapatkan output dari solusi ketiga dengan cara yang baik:

echo "$var"

dan juga dengan cara yang buruk:

echo $var
52
MLSC

Hanya untuk berbeda:

MOREF=$(Sudo run command against $VAR1 | grep name | cut -c7-)
24
DigitalRoss

Jika Anda ingin melakukannya dengan perintah multiline/multi/s maka Anda dapat melakukan ini:

output=$( bash <<EOF
#multiline/multiple command/s
EOF
)

Atau:

output=$(
#multiline/multiple command/s
)

Contoh:

#!/bin/bash
output="$( bash <<EOF
echo first
echo second
echo third
EOF
)"
echo "$output"

Keluaran:

first
second
third

Menggunakan heredoc Anda dapat menyederhanakan banyak hal dengan mudah dengan memecah kode baris tunggal panjang Anda menjadi multiline. Contoh lain:

output="$( ssh -p $port [email protected]$domain <<EOF 
#breakdown your long ssh command into multiline here.
EOF
)"
13
Jahid

Saat mengatur variabel, pastikan Anda memiliki NO Spaces sebelum dan/atau setelah tanda = . Secara harfiah menghabiskan satu jam mencoba mencari ini, mencoba semua jenis solusi! Ini tidak keren.

Benar:

WTFF=`echo "stuff"`
echo "Example: $WTFF"

Will Fail with error: (barang: tidak ditemukan atau serupa)

WTFF= `echo "stuff"`
echo "Example: $WTFF"
13
Emil

Anda harus menggunakan keduanya

$(command-here)

atau

`command-here`

contoh

#!/bin/bash

VAR1="$1"
VAR2="$2"

MOREF="$(Sudo run command against "$VAR1" | grep name | cut -c7-)"

echo "$MOREF"
8
Diego Velez

Ini adalah cara lain, baik untuk digunakan dengan beberapa editor teks yang tidak dapat menyoroti dengan benar setiap kode rumit yang Anda buat.

read -r -d '' str < <(cat somefile.txt)
echo "${#str}"
echo "$str"
6
Aquarius Power

Anda dapat menggunakan tanda centang kembali (juga dikenal sebagai aksen kuburan) atau $(). Seperti-

OUTPUT=$(x+2);
OUTPUT=`x+2`;

Keduanya memiliki efek yang sama. Tetapi OUTPUT = $ (x + 2) lebih mudah dibaca dan yang terbaru.

6
Pratik Patil

Beberapa mungkin menemukan ini berguna. Nilai integer dalam substitusi variabel, di mana triknya menggunakan kurung ganda $(()):

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
4
Gus

Berikut ini dua cara lagi:

Harap diingat bahwa ruang sangat penting di bash . Jadi, jika Anda ingin perintah Anda dijalankan, gunakan apa adanya tanpa memasukkan spasi lagi.

  1. berikut memberikan harshil ke L dan kemudian mencetaknya

    L=$"harshil"
    echo "$L"
    
  2. berikut memberikan output dari perintah tr ke L2. tr sedang dioperasikan pada variabel L1 lainnya.

    L2=$(echo "$L1" | tr [:upper:] [:lower:])
    
4
Harshil