나는 retropie에서 중복 이름 지정 문제를 수정하는 간단한 bash 스크립트를 작성 중입니다.
스크립트 자체는 gameslist.xml 파일에서 두 번 이상 언급 된 이름을 가져 와서 나중에 사용할 수 있도록 배열에 저장합니다.
다음과 같이 인덱스에서이 배열을 반복합니다.
pi@retropie:~ $ for game in ${game_array[@]:0:10} ; do echo $game; done
첫 번째 요소를 10 번째 요소 (예 ${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
필드 구분자가 새 줄로 설정되었으므로 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
간단히 말해서 필드 / 단어 분할을 명시 적으로 원하지 않는 한 배열 확장 주위에 따옴표를 사용해야합니다 . "$@"
각 위치 매개 변수를 별도의 단어로 확장하고 마찬가지로 "${a[@]}"
. 확장하면 "${a[@]:0:2}"
.
즉, 여전히 Bash에서 불일치하는 것처럼 보이며 사용한 것은 귀하의 경우에서 작동해야합니다 (값에 glob 문자가없고 필드 분할이 IFS
적절하게 설정 되어 처리 되기 때문입니다).
전체 어레이 작동 :
$ 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에서도 작동하며 .NET에 의존 할 필요가 없기 때문에 값을있는 그대로 원할 때 더 좋습니다 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
. 버그 리포트를 올렸습니다.
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다