Czy przekształcić tablicę w argumenty polecenia?

39

Mam tablicę „opcji” polecenia.

my_array=(option1 option2 option3)

Chcę wywołać to polecenie w skrypcie bash, używając wartości z tablicy jako opcji. Tak więc command $(some magic here with my_array) "$1"staje się:

command -option1 -option2 -option3 "$1"

Jak mogę to zrobić? Czy to możliwe?

Ktoś nadal używa ciebie MS-DOS
źródło
1
Więc chcesz dodać -na początku każdego słowa w my_array?
Kevin
@Kevin: Tak i uruchom go. Wszystkie wiersze znajdują się w tym samym skrypcie bash. Pytam o to, ponieważ te same opcje będą używane w wielu miejscach w skrypcie, więc zamiast kopiować je wszystkie, pomyślałem o tablicy.
Ktoś nadal cię używa MS-DOS,
1
Może się to wydawać bezcelowe, ale jeśli tworzysz duże skrypty powłoki, być może powinieneś przyjrzeć się perlowi, tego typu rzeczy są bardzo łatwe do zrobienia.
alfa64

Odpowiedzi:

43

Wolałbym prosty bashsposób:

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

Jednym z powodów tego są spacje. Na przykład, jeśli masz:

my_array=(option1 'option2 with space' option3)

Rozwiązania sedoparte na tym przekształcą go -option1 -option2 -with -space -option3(długość 5), ale powyższe bashrozszerzenie przekształci go w -option1 -option2 with space -option3(długość nadal 3). Rzadko, ale czasami jest to ważne, na przykład:

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
człowiek w pracy
źródło
Jeśli dobrze rozumiem, to podstawienie zmiennej nie może być opakowane w funkcję ani przypisane do zmiennej, prawda? Musi przejść bezpośrednio do wywołania polecenia.
Konrad Rudolph
1
@KonradRudolph, można przypisać go do innej zmiennej, tak długo, jak to zrobić, jak przypisanie tablicy: somevar=("${my_array[@]/#/-}")(Uwaga nawias wokół wartości). Potem oczywiście trzeba zachować go jako tablicę obsługi podczas korzystania z niego: echo "${somevar[@]}". Jeśli chodzi o funkcje, możliwości językowe są zbyt ograniczone. Można przekazać tablicę: somefunc "${my_array[@]/#/-}", a następnie wewnątrz trzeba będzie go w $@: function somefunc() { echo "$@"; }. Ale to samo $@będzie zawierało również inne parametry, jeśli istnieje, i nie ma innego sposobu na zwrócenie zmodyfikowanej tablicy niż standardowe wyjście.
manatwork
Dziwne, nie działa z zsh. Za pierwszym razem natknąłem się na coś, co działa bash, ale nie zsh.
Cześć Anioł
@ Hi-Angel, czy na pewno użyłeś @indeksu tablicy? Poddałem go testowi z zsh 5.5.1 i jedyną różnicą, jaką zauważyłem, było to, że zsh prefiksował każdy element, gdy napisano jako ${my_array[@]/#/-}, podczas gdy bash zrobił to również dla *indeksu dolnego.
manatwork
Och, przepraszam, mogłem coś spieprzyć, naprawdę działa dla mnie!
Cześć Anioł
2

Nie przetwarzałem, że jest w tablicy i myślałem, że jest oddzielony spacjami w ciągu. To rozwiązanie będzie z tym działało, ale biorąc pod uwagę, że jest to tablica, przejdź do rozwiązania manatwork ( @{my_array[@]/#/-}).


Nie jest tak źle z sedpodpowłoką. To, jak łatwa jest regex, zależy od tego, co możesz zagwarantować na temat opcji. Jeśli wszystkie opcje to jedno „słowo” ( a-zA-Z0-9tylko), wystarczy prosta początkowa granica słowa ( \<):

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

Jeśli twoje opcje mają inne postacie (najprawdopodobniej -), będziesz potrzebować czegoś bardziej złożonego:

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

^dopasowuje początek wiersza, [ \t]dopasowuje spację lub tabulator, \|dopasowuje dowolną stronę ( ^lub [ \t]), \( \)grupy (dla \|) i zapisuje wynik, \<dopasowuje początek słowa. \1zaczyna zastępowanie od zachowania pierwszego dopasowania z parens ( \(\)) i -oczywiście dodaje myślnik, którego potrzebujemy.

Działają z gnu sed, jeśli nie działają z twoim, daj mi znać.

A jeśli będziesz używać tej samej rzeczy wiele razy, możesz po prostu obliczyć to raz i zapisać:

opts="$(echo $my_array | sed 's/\(^\|[ \t]\)\</\1-/g')"
...
command $opts "$1"
command $opts "$2"
Kevin
źródło
Nie działało to z Mac OS X sed, więc musiałem użyć gsed(zainstalowałem używając homebrew). Kolejna rzecz: zamiast tego echo $my_arraymusiałem zrobić, echo ${my_array[@]}aby uzyskać wszystkie przedmioty my_array: echo $my_arraydawałem mi tylko pierwszy element. Ale dzięki za odpowiedź i wyjaśnienie wyrażenia regularnego, szczególnie na temat „granicy słów”, jest to niezwykle przydatne. :)
Ktoś nadal cię używa MS-DOS
Chciałbym wyjść ze skryptu, jeśli sed systemu nie jest zgodny z tą funkcją granicy słów. Jak mam to zrobić? Drukujesz wersję sed i porównujesz ją? Z której wersji sed dodano tę funkcję?
Ktoś nadal cię używa MS-DOS
1
@ SomebodystillusesyouMS-DOS Moją pierwszą myślą jest bezpośrednie sprawdzenie, czy to działa - [ $(echo x | sed 's/\</y/') == "yx" ] || exit.
Kevin
2
Spowoduje to uszkodzenie, jeśli którykolwiek z elementów tablicy będzie zawierał znaki specjalne, najbardziej oczywiście i nieuchronnie białe znaki.
Gilles „SO- przestań być zły”
1
@ SomebodystillusesyouMS-DOS Gilles ma rację, powinieneś zmienić swoją akceptację na manatwork.
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'

źródło