bash에서 입력을 반복하고 명령을 실행하는 범용 함수?

bash에서 입력을 반복하고 명령을 실행하는 범용 함수?

어떻게 분리되어 있는지에 관계없이 입력을 반복하고 명령을 실행하는 함수를 만들려고 합니다.

function loop {
    # Args
    #     1: Command
    #     2: Inputs
    for input in "$2" ; do                     
        $1 $input
    done
}
declare -a arr=("1" "2" "3")

$ loop echo "$arr[@]"
1

$ loop echo 1 2 3
1

$ loop echo $arr
1

그러나 따르면이것대답은 for .. in ..배열에서 작동합니다.

for item in "${arr[@]}" ; do
   echo "$item"
done

공백으로 구분된 값에서도 작동합니다.

for item in 1 2 3 ; do
   echo "$item"
done

간단히 말해서, 매개변수를 전달할 때 "${arr[@]}"효과를 어떻게 얻을 수 있습니까?1 2 3

\n또한 이 반복 개념을 파일과 같이 구분된 콘텐츠 와 같은 모든 종류의 구분된 항목으로 확장할 수 있습니까 ? Python에는 개념이 있습니다 iterators. bash에도 비슷한 것이 있습니까?

답변1

배열을 올바르게 호출하지 않았습니다. $arr배열의 첫 번째 요소로만 확장되며 $arr[@]리터럴 문자열이 추가되는 첫 번째 요소로 확장됩니다 [@].

배열의 모든 요소를 ​​호출하려면 다음을 사용하십시오."${arr[@]}"

또 다른 문제는 $2두 번째 위치 매개변수만 포함되어 있고 세 번째, 네 번째, 다섯 번째 등을 반복하려고 한다는 것입니다. 모두 에 저장됩니다 $@.

목표를 달성하려면 다음을 수행할 수 있습니다.

function loop {
    local command=$1
    shift
    for i in "$@"; do
        "$command" "$i"
    done
}

이는 첫 번째 위치 인수로 설정된 command다음 $@나머지 위치 인수를 반복하는 데 사용할 수 있도록 이동됩니다. 그런 다음 배열을 올바르게 호출하기만 하면 됩니다.

$ declare -a arr=("element1" "element2" "element3")
$ loop echo "${arr[@]}"
element1
element2
element3
$ loop printf 'hello ' 'world\n'
hello world
$ loop touch file1 file2 file3
$ ls
file1  file2  file3

이 함수가 다양한 구분 기호를 허용하도록 하려면 다음을 수행할 수 있습니다.

function loop {
    local command=$1
    local delim=$2
    shift 2
    set -- $(tr "$delim" ' ' <<<"$@")
    for i in "$@"; do
        "$command" "$i"
    done
}

즉, 두 번째 매개변수를 통해 사용할 구분 기호를 지정해야 합니다. 예를 들면 다음과 같습니다.

$ loop echo '|' 'one|two|three'
one
two
three
$ loop echo '\n' "$(printf '%s\n' 'one' 'two' 'three')"
one
two
three

그러나 여기에는 몇 가지 버그가 있습니다(사용자 정의 구분 기호를 지정하면 여전히 공백으로 구분됩니다).

답변2

코드에 구문 오류가 있습니다. 함수 호출에서 배열을 각 요소로 확장하는 목록(개별적으로 참조됨)을 loop사용합니다 . 이는 표시된 루프에서 수행하는 작업 이며, 함수를 호출할 때 수행해야 하는 작업은 다음과 같습니다."${arr[@]}"arrfor

loop echo "${arr[@]}"

또한 함수는 전달한 명령의 이름을 선택한 다음 나머지 인수를 반복해야 합니다.

loop () {
    local cmd=$1; shift
    for arg do
        "$cmd" "$arg"
    done
}

여기서는 첫 번째 매개변수를 변수 cmd(명령)에 할당한 다음 shift매개변수 목록에서 해당 매개변수를 제거합니다. 이제 인수 목록에는 반복하려는 문자열만 포함됩니다.

그런 다음 루프는 나머지 각 인수에 대해 명령을 차례로 호출합니다.

이는 제한된 방식으로 유틸리티의 목적을 복제하며 xargs유틸리티를 사용하여 함수를 다시 구현할 수 있습니다(인수 중 하나에 개행 문자가 포함될 것으로 예상하지 않는 한, 이 경우 옵션을 로 조정해야 합니다 xargs).

loop () {
    local cmd=$1; shift
    printf '%s\n' "$@" | xargs -L 1 "$cmd"
}

xargs유틸리티는 데이터가 표준 입력을 통해 전달될 것으로 예상 하므로 printf주어진 각 인수를 loop자체 줄에 사용하고 인쇄하도록 준비합니다(또한 xargs사용된 각 줄바꿈으로 구분된 인수에 대해 주어진 유틸리티가 한 번 호출되도록 지시합니다 -L 1).

이를 통해 우리는 where is some number of process to run in Parallel을 사용하여 xargs병렬 프로세스를 시작하는 등 구현의 다른 기능 중 일부를 사용할 수 있습니다.-P nn

시험:

$ cat script.sh
loop () {
    local cmd=$1; shift
    printf '%s\n' "$@" | xargs -L 1 "$cmd"
}

arr1=(1 2 3)
arr2=("hello world" "home sweet home")

loop echo "${arr1[@]}"
loop echo "${arr2[@]}"
$ bash script.sh
1
2
3
hello world
home sweet home

답변3

루프는 GNU Parallel과 매우 유사합니다.

declare -a arr=("1 a" "2 b" "3 c")
var1="1 a,2 b,3 c"
var2="1-a 2-b 3-c"
parallel -j1 echo ::: "${arr[@]}"
parallel -j1 -d , echo ::: "$var1"
parallel -j1 echo ::: $var2

-j1한 번에 하나의 작업을 강제로 실행합니다.

관련 정보