掘削

掘削

式の結果(つまり、コマンドの出力)を変数に代入し、それに対処したいと思います。たとえば、それを文字列に関連付けてからエコーします。これが私が得るものです:

#!/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実行時に印刷されます。

私は何を見逃していますか?

答え1

シェル割り当ては、等号の後にスペースがない単語です。だからあなたが書いたのはnull値を割り当てることですthefile。さらに、割り当てはコマンドとともにグループ化されるため、thefile環境変数が生成され、割り当てはその特定のコマンドに対してローカルです。つまり、呼び出し側だけがls割り当てられた値を表示できます。

コマンドの出力をキャプチャしようとしているので、以下を使用する必要があります。コマンドの置き換え:

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

(一部の文献は代替構文を示していますthefile=`ls …`。逆引用符の構文は、時々逆引用符内の引用が奇妙であることを除いて、ドル括弧の構文と同じですので、使用してください$(…)。)

スクリプトに関する追加の注:

  • -t(時間でソート)と-U(GNUでソートされていない)を組み合わせることlsは意味がありません-t

  • 一致するスクリーンショットを使用するよりもワイルドカードを渡し、それを使用して最初のファイルをキャプチャする方がきれいになりますgreplshead

      thefile=$(ls -td -- *"Screen Shot"* | head -n 1)
    
  • 通常一つ出力の解析に関する悪い考えls。ファイル名に印刷できない文字が含まれていると、大幅に失敗する可能性があります。ただし、これがないと、日付でファイルを並べ替えるのは難しいですls。したがって、ファイル名に印刷できない文字やバックスラッシュがないことがわかっている場合は、これが許容されるソリューションです。

  • 変数の置換には常に二重引用符を使用してください。つまり、ここに書いてください

      echo "Most recent screenshot is: $thefile"
    

    二重引用符がないと変数値が再び拡張されるため、スペースやその他の特殊文字が含まれていると問題が発生する可能性があります。

  • 行の末尾にはセミコロンは必要ありません。重複しますが無害です。

  • シェルスクリプトでは、通常、次のものを含めるのが最善です。set -e。これは、コマンドが失敗した場合(ゼロ以外の状態を返す)と、シェルが終了するように指示します。

findGNUがありsort(特に組み込まれていないLinuxまたはCygwinを実行している場合)、最新のファイルを見つける別の方法があります。findファイルとその日付をリストしてからsortandを使用します(ここではNULで区切られたレコードを読み取るとしますread)。 )最新のファイルを抽出します。bashzsh-d ''

IFS=/ read -rd '' ignored thefile < <(
  find -maxdepth 1 -type f -name "*Screen Shot*" -printf "%T@/%p\0" |
    sort -rnz)

bashの代わりにzshでこのスクリプトを作成したい場合は、zshから最新のファイルをキャプチャする簡単な方法があります。グローバル予選名前だけでなくファイルメタデータにもワイルドカードの一致が許可されます。(om[1])パターンに続く部分はglob修飾子です。om一致するアイテムは、年齢が増加する基準でソートされ(つまり、変更時間に応じて最新のアイテムから)、[1]最初の一致のみが抽出されます。完全一致は技術的に配列なので、括弧内に入れる必要があります。なぜなら、globbingはファイルのリストを返すからです。これは[1]、この特定のケースでは、リストに(最大)1つのファイルが含まれていることを意味しても同じです。

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

答え2

複数行/コマンドを使用してこれを行うには、次のようにします。

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

答え3

完全性のために、他のシェルで次のことを行います。

ボンシェル

1970年代後半、Bourneシェルはコマンド置換を導入しました。今日では使用されていませんが、多くのシェルの構文はそのシェルの構文に基づいています。

var=`any shell code`

子プロセスで解釈されると、any shell code出力はパイプに移動されます。その間、シェルはパイプのもう一方の端から出力を読み取り、それを$var変数に保存します。

しかし、参考にしてくださいみんなこの出力の末尾の改行は削除されます。

Bourneシェルは配列変数をサポートしていませんが、次のコマンドを使用してコマンドで出力された単語を位置引数($1$2...)に格納できます。

set -- `some code`

または:

set x `some code`; shift

以前のバージョンでは--サポートされていません。

、末尾の改行除去に加えて、出力は-ベースの分割+ワイルドカードの影響を受けますsome code$IFSたとえば、一部のコードが出力されて含まれてfoo,/*<newline><newline>いる$IFS場合は、,非表示のすべてのファイルが$1含まれ、残りのパラメータはです。/foo/

掘削

また、1970年代後半から1980年代初頭まで、当時非常に人気があり、tcsh多くの欠点にもかかわらず、一部のシステムでまだ生き残っていました。

set array = `some code`

出力分割some code(空白、タブ、または改行基準)の結果単語を$arrayリスト変数に保存します。

set array = "`some code`"

改行でのみ分割することを除けば同じです(の要素は$array出力の空でない行になります)。

ksh88やPOSIXなどのシェル。

今日sh、標準のsh言語インタプリタの1つ以上の実装は、主にDavid Kornによって書かれ、Bourneシェルでいくつかの修正および改善されたシェルの最後の進化であるksh88のサブセットに基づいています。これには、bash、dash、ksh、yash、mksh、zshが含まれます(これらの多くの場合、sh仕様の準拠はいくつかのオプションで有効にする必要があるか呼び出されますsh)。

var=$(any shell code)

var=`...`これは、ネストをより簡単にし、バックスラッシュの解釈を混乱させないことを除いて、Bourneシェルと同様に機能します。

ksh には配列がありますが、POSIX sh 仕様には配列サポートは含まれません。

rcとデリバティブ

rc1980年代後半、Research Unix V10とplan9のシェルで、かつてUnixの後継製品でした。いくつかの派生物を生成したシェルのパブリックドメインレプリカもあります。少なくともそれはesすべてですakanga。上記の構文よりはるかに優れた構文がありましたが、残念ながら実際には理解されていません。

array = `cmd
array = ` {any shell code}

保存された出力はany shell code文字$ifsに分割されます$array

array = `` (chars) {any shell code}

同じです。分割するcharsのではなく、指定した値を使用するだけです$ifs。を使用すると、var = ``(){shell code}出力を分割せずに正確に保存できます(実際にこれをすぐに実行できる唯一のシェル)。

ケシ

kshは、1980年代初頭に配列を導入した最初のBourne様シェルでした。構文は次のとおりです。

set -A array -- $(some code)

Bourneシェルと同様に、末尾の改行の削除、$IFS-分割、およびワイルドカード操作を実行します。

some command | read var1 var2 var3

出力の最初の行を読み込んでsome command分割し$IFS(バックスラッシュを使用して区切り文字と改行文字をエスケープできます)、結果をこれらの変数に保存するためにも使用できます。

readまた、zshでも機能しますが、サブシェルで実行されているbash、yash、またはpdksh / mkshなどの他のksh様シェルでは機能しません(sh標準では発生するかどうかを指定しないため、作成できません)ポータブル)を使用してくださいsh。 Bashはshopt -s lastpipeシェルの非対話式呼び出しを容易にします。

some code | read -A array

最初の行の単語が配列要素に格納されることを除いて同じです(オプションは独自の組み込みオプションにbash名前が変更されます)。-aread

kshも共同プロセスを導入します。

some command |&
IFS= read -r first_line <&p
IFS= read -r second_line <&p

たとえば、これは出力の最初と2番目の行を各変数として読み取るために使用できますsome command

zshとbashは後で別の構文を使用して共同プロセスのサポートを追加しました。

扱いにくい

zsh(Bourneに似た別のシェルですが、cshとrc機能もあります)は1991年(最初のバージョンが前年にリリースされてから数ヶ月後)バージョン2.0で配列サポートを導入しました。

array=( $(some code) )

改行の削除とIFS分割(ワイルドカードではない)を実行し、結果の単語を配列要素に割り当てます。

この構文は後で1993年にksh93と1996年にbash 2.0によってコピーされましたが、ksh88のように最上位にグローブを行いました。

$IFS以下以外のものと分離zsh:

array=( ${(f)"$(some code)"} ) # split on lineFeed aka newline
array=( ${(0)"$(some code)"} ) # split on NUL
array=( ${(s[string])"$(some code)"} ) # split on any string

zshまた、変数にNUL文字を格納できる唯一のシェルなので、これらの文字を含むコマンドの出力をブロックしない唯一のシェルです。 NULは実際には$IFSinのデフォルトですzsh(他のBourneと同様のシェルと同様に、スペース、タブ、および改行文字を除く)。

some command | IFS= read -rd '' var

some command出力の最初のNUL文字まで保存するために使用できます$var。 NULはテキストに現れないので、テキストをそのまま保存する方法です。-dksh93で-d ''NULを区切るのはbash / zsh追加です。

zshはまた、任意の数の文字を読み取る(もともとはキーストロークを読み取るためのものですが、読み取るfdを指定することと組み合わせると任意の文字に使用できます)など、いくつかのreadオプションを追加しました。オプション/関連する意味が後で追加されました。-k-uksh93bash-N-n

some command | read -u0 -k10 var

some command出力にの最初の10文字を保存します$var

sysreadモジュールの構文を使用して、システムコール用のネイティブインタフェースzsh/systemとしてブロックの入力を読み取ることもできます。read()

同じ名前のモジュールに組み込まれている機能を使用して、疑似端末ペアを介しzptyてコマンドと対話することもできますexpect

クッシュ 93

1993年後半に作者が発表したkshを完全に書き直したこのバージョンはbash 2+(そしてある程度zshとmksh)に大きなインスピレーションを与えました。

var=${
  any shell code
}

var=$(any shell code)これは、サブシェル環境で実行されないことを除いて同じですany shell code。つまり、シェルは同じである必要はなく、後で環境を復元し、修正はその後もそのまま維持されるため、やや効率的です。

最新バージョンですmksh

強く打つ

readarray array < <(some command)

配列要素に行some command(オプションを使用して削除できる区切り文字を含む)を保存します。いわゆるプロセス交換が1980年代半ばのkshに追加されましたが、最初はリダイレクトターゲットとして使用できませんでした(この問題ははるかに後でksh93で修正されました)。-t$array<(...)

Bash 4.4+では、NULを含む改行に加えて他の区切り文字を使用できます。

readarray -t -d '' array < <(find . -print0)

findたとえば、出力からNULで区切られたレコードの内容を格納するために使用できます$array

次のようにすることもできます。

read var1 var2 < <(some command)

オプションが有効になっていない場合でも機能しますlastpipe(zshでも機能します)。

ヤッシュ

read var1 var2 <(any shell code)

kshのプロセス置換のように見えますが、その中の機能はプロセスリダイレクトと呼ばれ、名前付きパイプのパスに拡張する代わりに、対応するfd(ここでは0)がもう一方の端が接続されているパイプラインに割り当てられます。パイプの読み取り側のコマンドです。

構文は他のシェルとはかなり異なる比較的後発者です(目標はまだ変更されていますが、はるかに優れている場合が多い)。

set array (some shell code)

シェルコード出力の各行を配列の要素に割り当てます。

some command | read var1 var2

最初の行は読み取られ、分割$IFS(変更することができます)または区切り文字として-d delim保存されます。行の単語を配列に保存します。$var1$var2read -a array

some command | read -L var1 var2

他の変数の最初の2行について。

some command | read -z var

最初のNULより前のすべての内容(したがって、テキスト出力のすべての内容)は$var

関連情報