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.