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


76

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

#!/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、実行時に印刷されているように見えます。


回答:


108

シェル割り当ては、等号の後にスペースがない単一の単語です。したがって、あなたが書いたものは空の値を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修飾子があるため、最新のファイルをキャッチするはるかに簡単な方法があります。(om[1])パターンの後の部分は、glob修飾子です。om年齢の昇順(つまり、変更時間、新しい順)で一致をソートし[1]、最初の一致のみを抽出します。Globbingはファイルのリストを返すので[1]、この特定のケースではリストに(最大で)1つのファイルが含まれている場合でも、技術的には配列であるため、一致全体を括弧で囲む必要があります。

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

7
うわー!私が望んでいたよりも多くの情報。ご回答ありがとうございます。あなたがこれに費やしたすべての努力に本当に感謝しています!あなたは私に、本当に、本当に学ぶべきことがたくさんあることを見せてくれました。私はbashで本を買うつもりです:P。
ネイサンG.

3
それが私が決定的な答えと呼ぶものです!:)
アレックス

4

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

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

これはいい答えです。コマンドの一部として変数を指定する方法はありますか?例えばoutput=$(echo $someVariable)
ザック・スミス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.