나는 이 주제에 관해 이 사이트의 매우 많은 게시물을 따랐지만 여전히 뭔가 잘못하고 있는 것이 분명합니다...
내 목표는 두 개의 서로 다른 배열에 값을 정의한 다음 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
ubstitute 명령을 하나의 입력으로 수집하여 sed
다음을 수행할 수도 있습니다.
for index in ${!defaultdirs[*]}
do echo "s#${defaultdirs[$index]}#${customdirs[$index]}#g"
done | sed -f- ~/Desktop/scripts/test_replace.txt
답변3
문제는 다음과 같습니다Shawn은 이미 지적했습니다.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/
또한 접두사 문자열과 final 을 일치시켜 대체를 좀 더 안정적으로 만들 수 있었습니다 "
.
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
위치 매개변수 목록의 맨 앞부분 요소를 이동하는 데 사용됩니다.