Bir diziyi bir komutun argümanlarına dönüştürmek?


39

Bir komutun "seçenekleri" dizisine sahibim.

my_array=(option1 option2 option3)

Dizi komutunu seçenekler olarak kullanarak bu komutu bir bash betiğinde çağırmak istiyorum. Yani, command $(some magic here with my_array) "$1"olur:

command -option1 -option2 -option3 "$1"

Nasıl yapabilirim? Mümkün mü?


1
Yani -her kelimenin başlangıcına eklemek ister misin my_array?
Kevin

@Kevin: Evet ve yürütün. Tüm satırlar aynı bash betiğinin içindedir. Bunu soruyorum çünkü aynı seçenekler senaryo içindeki birçok yerde kullanılacaktır, bu yüzden hepsini kopyalamak yerine bir dizi düşündüm.
Biri hala MS-DOS kullanıyor,

1
Bu anlamsız görünebilir ama büyük kabuk senaryoları yapıyorsanız belki perl'e bakmalısınız, bu tür şeyleri yapmak çok kolaydır.
alfa64

Yanıtlar:


43

Sade bir bashyolu tercih ederim :

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

Bunun bir nedeni boşluklar. Örneğin, varsa:

my_array=(option1 'option2 with space' option3)

Temel sedçözümler onu -option1 -option2 -with -space -option3(5) boyuna çevirir, ancak yukarıdaki bashgenişleme onu -option1 -option2 with space -option33 (uzun boylu 3) değerine çevirir. Nadiren, ama bazen bu önemlidir, örneğin:

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

Doğru anlarsam, bu değişken ikamesi bir işleve dahil edilemez, bir değişkene atanamaz, değil mi? Doğrudan komut çağırma işlemine girmesi gerekiyor.
Konrad Rudolph

1
@KonradRudolph, dizi ataması yaptığınız sürece onu diğer değişkene atayabilirsiniz: somevar=("${my_array[@]/#/-}")(Değerin etrafındaki parantezi not edin.) Ardından, onu kullanırken dizi olarak kullanmaya devam etmeniz gerekir echo "${somevar[@]}". İşlevlerle ilgili olarak, dilin olanakları ile sınırlısınız. Bir dizi geçirebilirsiniz: somefunc "${my_array[@]/#/-}"o zaman buna sahip olacak iç $@: function somefunc() { echo "$@"; }. Fakat aynı $@durum varsa diğer parametreleri de içerecektir ve değiştirilmiş diziyi stdout'tan döndürmenin başka bir yolu yoktur.
Manatwork

Tuhaf, zsh ile çalışmıyor. İlk seferinde bash'da çalışan fakat zsh'da olmayan bir şeye rastladım.
Hi-Angel

@ Hi-Angel, @dizi aboneliği olarak kullandığınızdan emin misiniz ? Ben zsh 5.5.1 ile bir test verdim ve fark ettiğim tek fark, zsh olarak her bir öğenin ne yazdığını ${my_array[@]/#/-}, bash da bunu *abonelik için yaptı.
Manat çalışması

Üzgünüm, bir şeyi batırmış olabilirim, gerçekten de benim için çalışıyor!
Hi-Angel,

2

Bir dizide olduğunu işlemedim ve bir dizede boşlukla ayrılmış olduğunu düşünüyordum. Bu çözüm bununla işe yarayacak, ancak bir dizi göz önüne alındığında, manatwork'ün çözümüyle ( @{my_array[@]/#/-}) geçin .


Bu çok kötü değil sedve bir denizaltıyla. Regex'in ne kadar kolay olduğu, seçenekler hakkında neleri garanti edeceğinize bağlıdır. Seçeneklerin tümü bir "sözcük" ise ( a-zA-Z0-9sadece), o zaman basit bir başlangıç ​​sözcük sınır ( \<) yeterli olacaktır:

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

Seçeneklerinizde başka karakterler varsa (büyük olasılıkla -), biraz daha karmaşık bir şeye ihtiyacınız olacak:

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

^satırın başlangıcıyla [ \t]eşleşir, bir boşlukla veya sekmeyle \|eşleşir, her iki tarafla ( ^veya [ \t]) eşleşir , \( \)gruplar (için \|) ve sonucu depolar, \<bir kelimenin başlangıcıyla eşleşir. \1ilk eşleşmeyi parens ( \(\)) ile değiştirerek işe başlar ve -elbette ihtiyacımız olan çizgiyi ekler.

Bunlar gnu sed ile çalışıyor, eğer seninle çalışmazsa, haberim olsun.

Aynı şeyi birden çok kez kullanacaksanız, bir kez hesaplamak ve depolamak isteyebilirsiniz:

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

Bu Mac OS X sed ile çalışmadı, bu yüzden kullanmam gerekiyordu gsed(kullanarak kurdum homebrew). Başka bir şey: Bunun yerine, tüm öğeleri almak echo $my_arrayiçin yapmam echo ${my_array[@]}gerekiyordu my_array: echo $my_arraybana sadece ilk elemanı veriyordu. Ancak regex'in cevabı ve açıklaması için, özellikle “kelime sınırı” hakkında teşekkürler, bu son derece yararlıdır. :)
Biri hala MS-DOS kullanıyor,

Sistemin sed'i bu kelime sınırı özelliğiyle uyumlu değilse komut dosyasından çıkmak istiyorum. Nasıl yaparım? Sed sürümü yazdırmak ve karşılaştırmak? Sed'in hangi sürümünden bu özellik eklendi?
Biri hala

1
@ SomebodystillusesyouMS-DOS İlk düşüncem, çalışıp çalışmadığını doğrudan kontrol etmektir - [ $(echo x | sed 's/\</y/') == "yx" ] || exit.
Kevin

2
Dizi öğelerinin herhangi biri, en açık ve açık şekilde boşluk bırakan özel karakterler içeriyorsa, bu kopar.
Gilles 'SO- kötülük olmayı'

1
@ SomebodystillusesyouMS-DOS Gilles haklı, kabul etmene manatwork yapmalısın.
Kevin

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'
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.