2つの配列で定義された変数でsedを使用する

2つの配列で定義された変数でsedを使用する

私はこのトピックについてこのサイトで多くの投稿をフォローしましたが、まだ私が何か間違っていることは明らかです...

私の目標は、2つの異なる配列に値を定義し、sedを使用して2番目の配列のテキストとして最初の配列で定義されたテキスト文字列を取得することです。

コードは以下のように表示されます。


#!/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

最初の問題:一重引用符で囲まれた文字列に拡張変数がありません。

2番目の問題:現状のままs///g最初の問題を修正した後、代替項目のスラッシュが原因でコマンドがハングします。別の区切り記号を使用してくださいs

sed3番目の(より小さい)問題:同じファイルで複数回実行されていますが、これは非常に効率的ではなく、-i内部編集オプションが非標準であり、異なる実装が異なる動作を提供します(人々が直面する一般的な状況)。変数は必要ありませんが、Mac OSバージョンには必要です。ファイルを編集して変更を保存するには、ed通常ex

1回の電話ですべての操作を実行できます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すべての代替コマンドを1つの入力として収集することもできます。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

2つの配列の2つの文字列セットのペアは、配列の1つを位置引数リストに割り当ててから、他の配列を繰り返しset実行します。各反復で、shift位置引数リストの先頭要素を移動します。

関連情報