bash - 変数展開 - シェルスクリプト 変数




どのように変数をBashでコマンドの出力に設定するのですか? (9)

私は次のような非常に簡単なスクリプトを持っています:

#!/bin/bash

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

echo $MOREF

コマンドラインからこのスクリプトを実行して引数を渡すと、出力が得られません。 しかし、 $MOREF変数に含まれるコマンドを実行すると、出力を取得できます。

私はスクリプト内で実行する必要のあるコマンドの結果をどのように取って変数に保存し、その変数を画面に出力するのかを知りたいですか?


私がコマンドから変数を設定するために使用するいくつかのbashトリック

2nd Edit 2018-02-12:特別な方法を追加しました。

2018-01-25 Edit:サンプル関数を追加する (ディスク使用量に関するvarsの設定用)

最初の簡単で古い互換性のある方法

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

ほとんど互換性のある、第2の方法

ネスティングが重くなるにつれて、このために括弧が実装されました

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

ネストされたサンプル:

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

複数の変数を読み込むbashismsで

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

もし私が欲しいのであれば、

array=($(df -k /))

あなたは配列変数を見ることができます:

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

次に:

echo ${array[9]}
529020

しかし、私はこれを好む:

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

最初のread fooはヘッダ行をスキップします(変数$fooにはFilesystem 1K-blocks Used Available Use% Mounted onようなものが含まれていFilesystem 1K-blocks Used Available Use% Mounted on

いくつかの変数を設定するサンプル関数:

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

注意:読みやすいように、 declare行は必須ではありません。

sudo cmd | grep ... | cut ...についてsudo cmd | grep ... | cut ... sudo cmd | grep ... | cut ...

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

(無駄なcat避けてください!これは1フォーク少ないです:

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

すべてのパイプ( | )はフォークを意味します。 別のプロセスを実行して、ディスクにアクセスし、ライブラリ呼び出しなどを行う必要があります。

したがって、 sedをサンプルとして使用すると、サブプロセスが1つのフォークに限定されます

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

bashismsと

しかし、多くの場合、小さなファイルを扱う多くのアクションでは、 bashは自分自身で仕事をすることができます。

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

または

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

変数の分割についてもっと詳しく...

私の答えを見てみましょう。 どのように文字列をBashの区切り文字に分割しますか?

代替:バックグラウンドで長時間実行されるタスクを使用してフォークを減らす

2回目の編集2018-02-12:複数のフォークを防ぐため

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

または

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

また、 datebc bcできるため、

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

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

各要求に対して新しいフォークを開始する必要はなく、 長時間実行されるバックグラウンドプロセスを使用してジョブを繰り返し実行することができます。

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

(もちろん、FD5と6は使用しないでください!)...そこから、あなたはこのプロセスを以下のように使うことができます:

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関数はGitHub.Comまたは自分のサイトにあります (Nota on github、 サイトには2つのファイルがあり、関数とデモは1つのファイルにまとめられています。

サンプル:

. 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を使用すると、簡単な構文で、かつdateに対してバックグラウンドタスクを使用できます。

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

そこから、バックグラウンドプロセスを終了したい場合は、彼の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

メインプロセスが終了するとすべてのfdが閉じられるので、必要ではありません。


アップデート (2018):正しい方法は

$(sudo run command)

間違った種類のアポストロフィを使用しています。 あなたは` 、not 'が必要です。 この文字は「バックティック」(または「重アクセント」)と呼ばれます。

このような:

#!/bin/bash

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

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

echo "$MOREF"

これは別の方法です。作成する複雑なコードをすべて正しく表示できないテキストエディタを使用するとよいでしょう。

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

ちょうど違うように:

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

もう2つの方法があります:

スペースはbash非常に重要であることに注意してください。 したがって、コマンドを実行する場合は、それ以上のスペースを導入せずにそのまま使用してください。

  1. 次に、harshilをLに割り当ててからそれを印刷します。

    L=$"harshil"
    echo "$L"
    
  2. 以下は、コマンドtr出力をL2に割り当てる。 trは別の変数L1で操作されています。

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

バッククォート( `command` )に加えて、私は読み易い$(command)使うことができ、入れ子にすることができます。

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

引用符( " )は、複数行の値を保持するために重要です。


変数を設定するときは、 =記号の前後に空白がないことを確認してください。 文字通りこれを理解しようと1時間を費やし、あらゆる種類のソリューションを試してみよう! これはクールではない。

正しい:

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

エラーで失敗する:(もの:見つからないか類似している)

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

彼らがすでにあなたに示しているように、あなたは 'バックティック'を使うべきです。

$(command)の代わりに$(command)も使えますが、読むのが簡単ですが、bashやkornシェル(およびそれらから派生したシェル)でのみ有効であることに注意してください。システムでは、古いバックティック表記を好むべきです。


複数行/複数のコマンド/ sで実行したい場合は、これを行うことができます:

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

または:

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

例:

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

出力:

first
second
third

heredocを使うと、長い単一行コードを複数行に分割することで、簡単に事を単純化することができます。 もう一つの例:

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




command-line