나는 이 주제에 관해 이 사이트에서 많은 게시물을 팔로우했지만 여전히 내가 뭔가 잘못하고 있다는 것이 분명합니다...
내 목표는 두 개의 서로 다른 배열에 값을 정의한 다음 sed를 사용하여 두 번째 배열의 텍스트로 첫 번째 배열에 정의된 텍스트 문자열을 검색하는 것입니다.
코드는 아래와 같이 표시됩니다.
#!/bin/bash
# define variables
defaultdirs=( Templates Documents Music Pictures Videos )
customdirs=( custom\/templates custom\/documents custom\/music custom\/pictures custom\/videos )
# replace text strings
for index in ${!defaultdirs[*]}
do
echo ${defaultdirs[$index]} will become ${customdirs[$index]}
sed -i 's/${defaultdirs[$index]}/${customdirs[$index]}/g' ~/Desktop/scripts/test_replace.txt
done
echo는 올바른 문자열을 출력하지만 텍스트 파일은 변경되지 않은 상태로 유지되므로 sed는 올바른 정보를 얻지 못합니다.
아이디어?
참고로 test_replace.txt 내용입니다
# This file is written by xdg-user-dirs-update
# If you want to change or add directories, just edit the line you're
# interested in. All local changes will be retained on the next run.
# Format is XDG_xxx_DIR="$HOME/yyy", where yyy is a shell-escaped
# homedir-relative path, or XDG_xxx_DIR="/yyy", where /yyy is an
# absolute path. No other format is supported.
#
XDG_DESKTOP_DIR="$HOME/Desktop"
XDG_DOWNLOAD_DIR="$HOME/Downloads"
XDG_TEMPLATES_DIR="$HOME/Templates"
XDG_PUBLICSHARE_DIR="$HOME/Public"
XDG_DOCUMENTS_DIR="$HOME/Documents"
XDG_MUSIC_DIR="$HOME/Music"
XDG_PICTURES_DIR="$HOME/Pictures"
XDG_VIDEOS_DIR="$HOME/Videos"
답변1
첫 번째 문제: 작은따옴표로 묶인 문자열에 확장된 변수가 없습니다.
두 번째 문제: 있는 그대로 s///g
첫 번째 문제를 수정한 후 대체 항목의 슬래시로 인해 명령이 중단됩니다. 다른 구분 기호를 사용하십시오 s
.
sed
세 번째(더 작은) 문제: 동일한 파일에서 여러 번 실행 중인데 이는 매우 효율적이지 않으며 -i
내부 편집 옵션이 비표준이며 서로 다른 구현이 서로 다른 동작을 제공합니다(사람들이 직면하는 일반적인 상황) 문제는 GNU 버전에는 매개변수가 필요하지 않지만 Mac OS 버전에는 필요하다는 것입니다. 파일을 편집하고 변경 사항을 저장하려면 일반적 ed
으로 ex
.
단 한 번의 전화로 모든 작업을 수행할 수 있습니다 ed
.
#!/bin/bash
# define variables
defaultdirs=(Templates Documents Music Pictures Videos)
customdirs=(custom/templates custom/documents custom/music custom/pictures custom/videos)
# replace text strings
(for index in ${!defaultdirs[*]}; do
echo "${defaultdirs[$index]} will become ${customdirs[$index]}" >&2
echo "g/${defaultdirs[$index]}/s|${defaultdirs[$index]}|${customdirs[$index]}|g"
done;
echo w) | ed -s test_replace.txt
X will become Y
표준 오류 대신 표준 출력으로 메시지를 보내는 것에 대한 대안입니다 ed
.공동 프로세스, 파이프를 사용하는 대신 개별 명령을 입력으로 리디렉션합니다.
#!/bin/bash
# define variables
defaultdirs=(Templates Documents Music Pictures Videos)
customdirs=(custom/templates custom/documents custom/music custom/pictures custom/videos)
coproc ED { ed -s test_replace.txt; } 2>/dev/null
# replace text strings
for index in ${!defaultdirs[*]}; do
echo "${defaultdirs[$index]} will become ${customdirs[$index]}"
echo "g/${defaultdirs[$index]}/s|${defaultdirs[$index]}|${customdirs[$index]}|g" >&${ED[1]}
done
printf '%s\n' w q >&${ED[1]}
wait $ED_PID
답변2
s
모든 대체 명령을 하나의 입력으로 수집 할 수도 있습니다 .sed
for index in ${!defaultdirs[*]}
do echo "s#${defaultdirs[$index]}#${customdirs[$index]}#g"
done | sed -f- ~/Desktop/scripts/test_replace.txt
답변3
문제는 다음과 같습니다.Sean이 지적했습니다., sed
생성한 스크립트에 구문 오류가 있기 때문입니다. 구문 오류는 동일한 문자를 구분 기호로 사용하는 명령 /
에서 이를 사용하려고 한다는 사실 에서 발생합니다.s
너노력하다/
배열의 문자열을 이스케이프 처리하여 이 문제를 해결 customdirs
하지만 실제로는 문자열에 이스케이프를 삽입해야 합니다 \\/
.\
대신 여기에 다른 접근 방식이 있습니다.
find_strings=( Templates Documents Music Pictures Videos )
replace_strings=( custom/templates custom/documents custom/music custom/pictures custom/videos )
set -- "${find_strings[@]}"
sed_stmts=( )
for replace_string in "${replace_strings[@]}"; do
# sed_stmts+=( -e 's,\("$HOME/\)'"$1"'",\1'"$replace_string"'",' )
# simpler, but less precise:
# sed_stmts+=( -e "s,$1,$replace_string," )
# alternatively:
# sed_stmts+=( -e "s/${1//\//\\/}/${replace_string//\//\\/}/" )
shift
done
sed "${sed_stmts[@]}" test_replace.txt >new-test_replace.txt
나는 또한 "$HOME/
접두사 문자열과 최종 "
.
이는 결국 sed
다음과 같이 호출됩니다.
sed -e 's,\("$HOME/\)Templates",\1custom/templates",' -e 's,\("$HOME/\)Documents",\1custom/documents",' -e 's,\("$HOME/\)Music",\1custom/music",' -e 's,\("$HOME/\)Pictures",\1custom/pictures",' -e 's,\("$HOME/\)Videos",\1custom/videos",' test_replace.txt
sed
이는 배열에 일련의 명령문을 작성한 sed_stmts
다음 sed
.
두 배열의 두 문자열 세트 쌍은 배열 중 하나를 위치 인수 목록에 할당한 다음 다른 배열을 반복하여 set
수행됩니다 . 각 반복에서 shift
위치 인수 목록의 맨 앞 요소를 이동합니다.