2개의 배열에 정의된 변수와 함께 sed 사용

2개의 배열에 정의된 변수와 함께 sed 사용

나는 이 주제에 관해 이 사이트의 매우 많은 게시물을 따랐지만 여전히 뭔가 잘못하고 있는 것이 분명합니다...

내 목표는 두 개의 서로 다른 배열에 값을 정의한 다음 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

모든 substitute 명령을 하나의 입력으로 수집하여 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_stmtssed

두 배열의 두 문자열 세트 쌍은 를 사용하여 배열 중 하나를 위치 매개변수 목록에 할당한 set다음 다른 배열을 반복하여 수행됩니다. 각 반복에서 shift위치 매개변수 목록의 맨 앞부분 요소를 이동하는 데 사용됩니다.

관련 정보