web-dev-qa-db-ja.com

コマンドの出力をシェル変数に割り当てるにはどうすればよいですか?

式の結果を変数に割り当てて文字列と連結し、それをエコーし​​たいのですが。ここに私が持っているものがあります:

#!/bin/bash
cd ~/Desktop;
thefile= ls -t -U | grep -m 1 "Screen Shot";
echo "Most recent screenshot is: "$thefile;

しかし、それは出力します:

Screen Shot 2011-07-03 at 1.55.43 PM.png
Most recent screenshot is: 

そのため、$thefileに割り当てられていないようで、実行時に出力されます。

82
Nathan G.

シェルの割り当ては単一の単語であり、等号の後にスペースはありません。したがって、あなたが書いたものは空の値をthefileに割り当てます。さらに、割り当てはコマンドでグループ化されるため、thefileが環境変数になり、割り当てはその特定のコマンドに対してローカルになります。つまり、lsの呼び出しだけが割り当てられた値を参照します。

コマンドの出力をキャプチャしたいので、 コマンド置換 を使用する必要があります:

_thefile=$(ls -t -U | grep -m 1 "Screen Shot")
_

(一部の文献は代替構文_thefile=`ls …`_を示しています。逆引用符の構文は、逆引用符内の引用が奇妙な場合があることを除いて、ドルかっこ構文と同等であるため、$(…)を使用してください。)

スクリプトに関するその他の注意:

  • _-t_(時間でソート)と_-U_(ソートしない)を組み合わせても意味がありません。 _-t_を使用してください。
  • grepを使用してスクリーンショットを一致させるのではなく、lsにワイルドカードを渡し、headを使用して最初のファイルをキャプチャする方が明確です。

    _thefile=$(ls -t *"Screen Shot"* | head -n 1)
    _
  • 一般的には lsの出力を解析するのは悪い考えです です。印刷不可能な文字を含むファイル名がある場合、これはかなりひどく失敗する可能性があります。ただし、lsがないとファイルを日付順に並べ替えることは困難です。そのため、ファイル名に印刷できない文字やバックスラッシュが含まれていないことがわかっている場合は、これは許容できる解決策です。

  • 常に変数の置換を囲む二重引用符を使用します、つまりここに書き込みます

    _echo "Most recent screenshot is: $thefile"
    _

    二重引用符がないと、変数の値が再展開され、空白やその他の特殊文字が含まれていると問題が発生します。

  • 行の終わりにセミコロンは必要ありません。それらは冗長ですが無害です。
  • シェルスクリプトでは、 _set -e_ を含めることをお勧めします。これは、コマンドが失敗した場合(ゼロ以外のステータスを返すことにより)終了するようにシェルに指示します。

GNU findがある場合(特に、組み込みでないLinuxまたはCygwinを実行している場合)、最新のファイルを見つける別の方法があります:findファイルを一覧表示しますそしてそれらの日付、およびsorttailを使用して最新のファイルを抽出します。

_thefile=$(find -maxdepth 1 -type f -name "*Screen Shot*" -printf "%T@ %p" |
          sort -k 1n | tail -n 1)
_

このスクリプトをbashではなくzshで記述したい場合、zshには glob qualifiers があり、名前だけでなくファイルでもワイルドカードの一致を許可するため、最新のファイルを簡単にキャッチできます。メタデータ。パターンの後の_(om[1])_部分はグロブ修飾子です。 omは、一致を年齢の昇順(つまり、変更時刻、新しいものが最初)で並べ替え、_[1]_は最初の一致のみを抽出します。 _[1]_がこの特定の場合にリストに(最大で)1つのファイルが含まれていることを意味する場合でも、グロビングはファイルのリストを返すため、完全一致は括弧で囲む必要があります。

_#!/bin/zsh
set -e
cd ~/Desktop
thefile=(*"Screen Shot"*(om[1]))
echo "Most recent screenshot is: $thefile"
_

Multiline/multiple command/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
4
Jahid