배열을 명령의 인수로 변환 하시겠습니까?


39

명령의 "옵션"배열이 있습니다.

my_array=(option1 option2 option3)

배열의 값을 옵션으로 사용하여 bash 스크립트 에서이 명령을 호출하고 싶습니다. 그래서, command $(some magic here with my_array) "$1"이된다 :

command -option1 -option2 -option3 "$1"

내가 어떻게 해? 가능합니까?


1
? -에서 각 단어의 시작 부분에 추가하고 싶 my_array습니까?
Kevin

@Kevin : 그렇습니다. 모든 줄은 동일한 bash 스크립트 안에 있습니다. 이 옵션은 스크립트 내부의 많은 장소에서 사용되므로 모든 것을 복사하는 대신 배열에 대해 생각했기 때문에 이것을 묻습니다.
누군가 아직도 당신을 사용합니다 MS-DOS

1
무의미 ​​해 보이지만 큰 쉘 스크립트를 만들고 있다면 아마도 펄을 조사해야 할 것입니다. 이런 일은 매우 쉽습니다.
alfa64

답변:


43

나는 평범한 bash방법을 선호합니다 :

command "${my_array[@]/#/-}" "$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

올바르게 이해하면이 변수 대체를 함수에 래핑하거나 변수에 할당 할 수 없습니다. 명령 호출로 직접 이동해야합니다.
Konrad Rudolph

1
: 당신이 배열 할당로처럼 @KonradRudolph, 당신은 긴과 같은 다른 변수에 할당 할 수 있습니다 somevar=("${my_array[@]/#/-}")(값 주위에 괄호를 참고.) 물론 당신이 그것을 사용하는 경우 배열로 처리를 계속해야 다음의 : echo "${somevar[@]}". 기능에 관해서는 언어의 가능성에 의해 너무 제한적입니다. 당신은 배열을 전달할 수 있습니다 somefunc "${my_array[@]/#/-}", 당신은 그것을해야합니다 내부 $@: function somefunc() { echo "$@"; }. 그러나 같은 $@경우 다른 매개 변수도 포함되며 stdout 이외의 수정 된 배열을 반환하는 다른 방법은 없습니다.
manatwork

이상하게도 zsh에서는 작동하지 않습니다. 처음으로 bash에서는 작동하지만 zsh에서는 작동하지 않는 것을 발견했습니다.
Hi-Angel

@ Hi-Angel, @배열 첨자로 사용 하시겠습니까? 나는 그것을 zsh 5.5.1로 테스트했으며 zsh ${my_array[@]/#/-}*첨자에 대해서도 zsh가 각 항목 앞에 접두사를 붙인 것을 발견 했습니다 .
manatwork

죄송합니다. 무언가를 망 쳤을 수도 있습니다.
Hi-Angel

2

배열에 있었고 공백으로 구분 된 문자열로 생각하고있었습니다. 이 솔루션은 그와 함께 작동하지만 배열이므로 manatwork의 솔루션 ( @{my_array[@]/#/-}) 과 함께하십시오 .


이것은 sed서브 쉘로 나쁘지 않습니다 . 정규식이 얼마나 쉬운지는 옵션에 대해 보장 할 수있는 것에 달려 있습니다. 옵션이 모두 하나의 "단어"( a-zA-Z0-9만)이면 간단한 시작 단어 경계 ( \<)로 충분합니다.

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

옵션에 다른 문자 (대부분 가능성이 있음 -)가있는 경우 조금 더 복잡한 것이 필요합니다.

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

^행의 시작과 [ \t]일치하고, 공백이나 탭과 \|일치하고, 측면 ( ^또는 [ \t]), \( \)그룹 ()을 일치시키고 \|결과를 저장하고 \<단어의 시작과 일치합니다. \1parens ( \(\)) 에서 첫 번째 일치 항목을 유지하여 교체를 시작하고 -물론 필요한 대시를 추가합니다.

그들은 당신과 함께 작동하지 않는 경우 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_array내가 할 필요 echo ${my_array[@]}에서 모든 항목을 얻을 수는 my_array: echo $my_array나에게 첫 번째 요소를주고 있었다. 그러나 특히 "단어 경계"에 대한 정규식에 대한 답변과 설명 덕분에 이것은 매우 유용합니다. :)
누군가가 여전히 MS-DOS를 사용함

시스템의 sed가이 단어 경계 기능과 호환되지 않으면 스크립트를 종료하고 싶습니다. 어떻게해야합니까? sed 버전을 인쇄하고 비교합니까? 이 기능이 추가 된 sed 버전은 무엇입니까?
누군가 아직도 당신을 사용합니다 MS-DOS

1
@ SomebodystillyousyouMS-DOS 내 첫 번째 생각은 그것이 작동하는지 직접 확인하는 것 [ $(echo x | sed 's/\</y/') == "yx" ] || exit입니다.
Kevin

2
배열 요소 중 하나에 특수 문자, 가장 명백하고 불가분의 공백이 포함되어 있으면 중단됩니다.
질 'SO-정지 존재 악마'

1
@ SomebodystillusesyouMS-DOS Gilles가 맞습니다. 승인을 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'
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.