配列をコマンドの引数に変換しますか?


40

コマンドの「オプション」の配列があります。

my_array=(option1 option2 option3)

配列の値をオプションとして使用して、bashスクリプトでこのコマンドを呼び出します。したがって、次のようにcommand $(some magic here with my_array) "$1"なります。

command -option1 -option2 -option3 "$1"

どうすればいいですか?出来ますか?


1
だから-、各単語の先頭に追加したいmy_arrayですか?
ケビン

@Kevin:はい、実行します。すべての行は同じbashスクリプト内にあります。これらの同じオプションがスクリプト内の多くの場所で使用されるため、私はこれを求めています。そのため、それらをすべてコピーするのではなく、配列について考えました。
誰かがまだあなたを使用してMS-DOS

1
無意味に思えるかもしれませんが、大きなシェルスクリプトを作成している場合は、おそらくperlを調べる必要があります。この種の作業は非常に簡単です。
alfa64

回答:


43

私はbash簡単な方法を好むでしょう:

command "${my_array[@]/#/-}" "$1"

その理由の1つはスペースです。たとえば、次の場合:

my_array=(option1 'option2 with space' option3)

sedベースのソリューションは、それを変換します-option1 -option2 -with -space -option3(長さ5)が、上記bash拡張はに変換します-option1 -option2 with space -option3(静止長3)。まれですが、時々これは重要です、例えば:

bash-4.2$ my_array=('Ffoo bar' 'vOFS=fiz baz')
bash-4.2$ echo 'one foo bar two foo bar three foo bar four' | awk "${my_array[@]/#/-}" '{print$2,$3}'
 two fiz baz three

正しく理解すれば、この変数置換を関数にラップすることも、変数に割り当てることもできませんよね?コマンド呼び出しに直接アクセスする必要があります。
コンラッドルドルフ

1
@KonradRudolph、配列の割り当てとして行う限り、他の変数に割り当てることができます:(somevar=("${my_array[@]/#/-}")値の周りの括弧に注意してください。)それから、使用するときはもちろん配列として扱い続ける必要があります:echo "${somevar[@]}"。機能に関しては、言語の可能性によって制限されすぎています。array:を渡すことができsomefunc "${my_array[@]/#/-}"ます。次に、内部に$@:を配置しfunction somefunc() { echo "$@"; }ます。ただし$@、存在する場合は他のパラメーターも含まれ、変更された配列を返す方法はstdout以外にはありません。
マナトワーク

奇妙なことに、zshでは動作しません。初めて、bshで機能するがzshでは機能しない何かに出会った。
ハイエンジェル

@ Hi-Angel、@配列の添字として使用しましたか?私はzsh 5.5.1でテストを行いましたが、唯一の違いは、zshがとして記述されたときに各アイテムの前に付けられるものに気づいただけ${my_array[@]/#/-}でしたが、bashは*下付き文字に対してもそれを行いました。
マナトワーク

ああ、申し訳ありませんが、私は何かをねじ込んだかもしれません、実際に私のために働いています!
ハイエンジェル

2

私はそれが配列にあることを処理せず、空白で区切られた文字列を考えていました。このソリューションはそれで動作しますが、それが配列である場合、manatworkのソリューション(@{my_array[@]/#/-})を使用します。


これはsedサブシェルで悪くありません。正規表現がどれだけ簡単かは、オプションについて何を保証できるかにかかっています。オプションがすべて1つの「単語」(a-zA-Z0-9のみ)である場合、単純な開始単語境界(\<)で十分です。

command $(echo $my_array | sed 's/\</-/g') "$1"

オプションに他の文字(ほとんどの-場合)がある場合、もう少し複雑なものが必要になります。

command $(echo $my_array | sed 's/\(^\|[ \t]\)\</\1-/g') "$1"

^行の先頭に[ \t]一致し、スペースまたはタブに\|一致し、どちらかの側(^または[ \t])に一致し、\( \)グループ(の場合)\|\<一致して結果を保存し、単語の先頭に一致します。 \1かっこ(\(\))からの最初の一致を保持することで置換を開始し、-もちろん必要なダッシュを追加します。

これらはgnu sedで動作しますが、あなたのものと動作しない場合はお知らせください。

また、同じものを複数回使用する場合は、一度計算して保存することもできます。

opts="$(echo $my_array | sed 's/\(^\|[ \t]\)\</\1-/g')"
...
command $opts "$1"
command $opts "$2"

これはMac OS Xのsedでは機能しなかったため、使用する必要がありましたgsed(使用してインストールしましたhomebrew)。別のこと:の代わりにecho $my_arrayecho ${my_array[@]}すべてのアイテムを取得するために行う必要がありましたmy_arrayecho $my_array最初の要素のみを与えていました。しかし、答えと正規表現の説明、特に「単語の境界」についてのおかげで、これは非常に便利です。:)
誰かがまだMS-DOSを使用しています

システムのsedがこの単語境界機能と互換性がない場合、スクリプトを終了したいと思います。どうすればいいですか?sedバージョンを印刷して比較しますか?この機能が追加されたsedのバージョンは?
誰かがまだMS-DOSを使用して

1
@ SomebodystillusesyouMS-DOS私の最初の考えは、それが機能するかどうかを直接確認することです- [ $(echo x | sed 's/\</y/') == "yx" ] || exit
ケビン

2
配列要素のいずれかに特殊文字が含まれている場合、これは明らかに、容赦なく空白文字です。
ジル 'SO-悪であるのをやめる

1
@ SomebodystillusesyouMS-DOS Gillesは正しいです。受け入れをマナトワークに変更する必要があります。
ケビン

0
[srikanth@myhost ~]$ sh sample.sh 

-option1 -option2 -option3

[srikanth@myhost ~]$ cat sample.sh

#!/bin/bash

my_array=(option1 option2 option3)

echo ${my_array[@]} | sed 's/\</-/g'
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.