인용하다! !

인용하다! !

저는 Retropie에서 중복된 이름 지정 문제를 해결하는 간단한 bash 스크립트를 작성하고 있습니다.

스크립트 자체는 gameslist.xml 파일에서 여러 번 언급된 이름을 가져와 나중에 사용할 수 있도록 배열에 저장합니다.

나는 다음과 같이 인덱스를 통해 이 배열을 반복했습니다.

pi@retropie:~ $ for game in ${game_array[@]:0:10} ; do echo $game; done

첫 번째부터 열 번째 요소(예: )를 가져오지만 ${game_array[9]}출력은 한 줄로 연결됩니다.

pi@retropie:~ $ for game in ${game_array[@]:0:10} ; do echo $game; done
R.B.I. Baseball '94 World Series Baseball '95 Mega Games 1 Bill Walsh College Football T2: The Arcade Game Sonic & Knuckles + Sonic the Hedgehog Sega Top Five Pyramid Magic Tecmo Super Baseball Super Chinese Tycoon

그러나 전체 배열을 반복하면 예상대로 새 줄이 출력됩니다.

pi@retropie:~ $ for game in ${game_array[@]}; do echo $game; done | head -10
R.B.I. Baseball '94
World Series Baseball '95
Mega Games 1
Bill Walsh College Football
T2: The Arcade Game
Sonic & Knuckles + Sonic the Hedgehog
Sega Top Five
Pyramid Magic
Tecmo Super Baseball
Super Chinese Tycoon

필드 구분 기호가 new line 으로 설정되어 있기 IFS='$\n'때문에 두 번째가 작동하지만 첫 번째가 작동하지 않는 이유를 평생 알 수 없습니까?

컨텍스트에 대한 전체 테스트 스크립트는 다음과 같습니다.

#!/bin/bash

user_input=$1
while [ -z "$user_input" ]; do
        echo "please enter the name of the system you want to fix the game list for"
        echo "(as it is labelled in /home/pi/RetroPie/roms)"
        read -r user_input
done

ls "/home/pi/RetroPie/roms/$user_input" >/dev/null 2>&1

if  [ "$?" -ne 0 ]; then
        echo "this doesn't appear to be a system installed here. exiting."
        exit 1
fi

games_to_fix()
{
        IFS=$'\n'
        console=$1
        filepath="/opt/retropie/configs/all/emulationstation/gamelists/$console/gamelist.xml"
        game_array=($(fgrep "<name>" "$filepath" | sort | uniq -c | sort -rn | awk  '$1 > 1 {print $0}'| cut -d ">" -f 2 | cut -d "<" -f 1))
        number_to_fix=($(fgrep "<name>" "$filepath" | sort | uniq -c | sort -rn | awk  '$1 > 1 {print $1}'))
}

get_new_name()
{
        mYpath=$1
        new_name=$(echo $mYpath | cut -d ">" -f 2 | cut -d "<" -f 1 | sed -e 's/\.\///g' | sed -e 's/\.7z//g')
}

games_to_fix $user_input

IFS=$'\n'
index=0
for i in ${number_to_fix[@]}; do
        loop=1
        for game in ${game_array[@]:$index:$i}; do
        #       for ind in $(eval echo {1..$i}); do
                line_number=$(fgrep -n "<name>$game</name>"  $filepath | awk '{print $1}' | cut -d : -f 1 | sed -e "${loop}q;d")
                path_line_number=$(expr $line_number - 1 )
                path=$(sed "${path_line_number}q;d" $filepath | cut -d : -f 2)
                get_new_name "$path"
                sed -i "${line_number}s/$game/$new_name/g" $filepath
                ((loop++))
        done
        index=$(expr index + $i);
done

답변1

간단히 말해서:배열 확장에는 따옴표를 사용해야 합니다.필드/단어 분할을 명시적으로 원하지 않는 한 이와 같습니다. "$@"각 위치 인수를 별도의 단어로 확장하고 마찬가지로 "${a[@]}". 확장하여 "${a[@]:0:2}".


IFS즉, Bash에는 여전히 불일치가 있는 것으로 보이며 사용 중인 내용이 귀하의 경우에는 작동해야 합니다(값에 전역 문자가 없고 필드 분할이 올바른 설정으로 처리되므로).

전체 배열의 효과를 얻으십시오.

$ IFS=$'\n'
$ a=("foo bar" "asdf ghjk")
$ printf "%s\n" ${a[@]}
foo bar
asdf ghjk

슬라이싱은 배열에서는 작동하지 않지만 다음에서는 작동합니다 $@.

$ printf "%s\n" ${a[@]:0:2}
foo bar asdf ghjk

$ set -- "aa bb" "cc dd"
$ printf "%s\n" ${@:1:2}
aa bb
cc dd

이것은 ksh와 zsh에서 작동하는데, 이는 여기서 Bash의 불일치를 강조합니다 (물론 zsh에는 동등한 구문이 있습니다) .

$ ifs=$'\n' ksh -c 'IFS="$ifs"; a=("foo bar" "asdf ghjk"); printf "%s\n" ${a[@]:0:2}'
foo bar
asdf ghjk
$ ifs=$'\n' zsh -yc 'IFS="$ifs"; a=("foo bar" "asdf ghjk"); printf "%s\n" ${a[@]:0:2}'
foo bar
asdf ghjk

인용된 버전은 Bash에서도 작동하며 에 의존할 필요가 없기 때문에 값을 있는 그대로 원할 때 더 좋습니다 IFS. IFS여기서는 배열 요소에 공백이 있어도 기본값이 잘 작동합니다.

$ unset IFS                         # uses default of $' \t\n'
$ printf "%s\n" "${a[@]:0:2}"
foo bar
asdf ghjk

따옴표가 없는 요소는 공백으로 연결된 것처럼 보입니다 ${a[@]:0:2}. 예를 들어 Bash에서 단어 분리가 발생하지 않을 때 발생하는 것과 약간 비슷합니다 str=${a[@]}. 그런 다음 평소대로 결과를 분할하려고 시도합니다 IFS. 예를 들어, 여기서는 두 번째 배열 요소 중간에 있는 개행 문자로 분할됩니다.

$ IFS=$'\n'
$ a=("foo bar" $'new\nline' "asdf ghjk");
$ printf ":%s\n" ${a[@]:0:3}
:foo bar new
:line asdf ghjk

위에서 언급했듯이 대부분의 경우 배열 확장 주위에 따옴표를 사용해야 하지만 그렇게 하는 ${a[@]:n:m}것처럼 여러 단어가 생성될 것이라고 여전히 가정할 수 있습니다.${a[@]}

여기의 동작은 Bash에 존재하는 것으로 보이며 4.4.12(1)-release이에 5.0.0(1)-alpha대한 버그 보고서를 게시했습니다.

답변2

인용하다
인용하다

인용하다

인용하다

인용하다! !

이것은 작동합니다:

$ game_array=("foo bar" "baz" "bam foo" "bar")

$ for game in "${game_array[@]:0:10}" ; do echo "$game"; done
foo bar
baz
bam foo
bar

관련 정보