Verwenden von sed mit Variablen, die in 2 Arrays definiert sind

Verwenden von sed mit Variablen, die in 2 Arrays definiert sind

Ich habe die zahlreichen Beiträge zu diesem Thema auf dieser Site verfolgt, aber ich mache offensichtlich immer noch etwas falsch …

Mein Ziel besteht darin, Werte in zwei unterschiedlichen Arrays zu definieren und dann mit sed eine im ersten Array definierte Textzeichenfolge mit der des zweiten Arrays zu durchsuchen.

Code unten:


#!/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 gibt die richtigen Zeichenfolgen aus, aber sed erhält nicht die richtigen Informationen, da die Textdatei unverändert bleibt.

Gedanken?

Als Referenz ist dies der Inhalt von 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"

Antwort1

Erstes Problem: In einfachen Anführungszeichen gesetzte Zeichenfolgen enthalten keine erweiterten Variablen.

Zweites Problem: So wie es ist, werden die Schrägstriche in Ihrem Ersatz den Befehl unterbrechen, s///gnachdem das erste Problem behoben wurde. Verwenden Sie ein anderes Trennzeichen für s.

Drittes (kleineres) Problem: Sie führen die Bearbeitung sedmehrmals über dieselbe Datei aus, was nicht sehr effizient ist. Außerdem -iist die Option zur Bearbeitung direkt vor Ort nicht standardmäßig und verschiedene Implementierungen, die diese Option bieten, reagieren unterschiedlich (das häufigste Problem ist, dass die GNU-Version kein Argument erfordert, die Mac OS-Version jedoch schon). Wenn Sie eine Datei bearbeiten und Änderungen speichern möchten, ist es normalerweise besser, einen dedizierten Dateieditor wie edoder zu verwenden ex.

Stattdessen alles mit einem edAufruf erledigen:

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

Alternative, die die X will become YNachrichten an die Standardausgabe statt an die Standardfehlerausgabe sendet und edin einemCoprozess, wobei einzelne Befehle an die Eingabe umgeleitet werden, anstatt eine Pipeline zu verwenden:

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

Antwort2

Sie können alle Ersatzbefehle auch sin einer Eingabe sammeln :sed

for index in ${!defaultdirs[*]}
  do   echo "s#${defaultdirs[$index]}#${customdirs[$index]}#g"
  done | sed -f- ~/Desktop/scripts/test_replace.txt

Antwort3

Das Problem, wieShawn hat bereits darauf hingewiesen, ist, dass Sie ein Skript mit einem Syntaxfehler erstellen sed. Der Syntaxfehler entsteht dadurch, dass Sie versuchen, /einen sBefehl zu verwenden, der dasselbe Zeichen als Trennzeichen verwendet.

Duversuchenum dem entgegenzuwirken, indem Sie die /Zeichenfolgen im customdirsArray maskieren, aber Sie müssten tatsächlich eine Maskierung in die Zeichenfolge \\/einfügen .\

Stattdessen gibt es hier einen anderen Ansatz:

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

Ich habe mir außerdem die Freiheit genommen, die Ersetzungen etwas zuverlässiger zu machen, indem ich auch die "$HOME/Präfixzeichenfolge und das Finale abgeglichen habe ".

sedDer Aufruf sieht dann folgendermaßen aus :

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

Dies geschieht durch den Aufbau einer Reihe von sedAnweisungen im Array sed_stmts, die dann in einem einzigen Aufruf von verwendet werden sed.

Die Paarung der beiden String-Sets in den beiden Arrays erfolgt, indem eines der Arrays mit der Liste der Positionsparameter zugewiesen wird setund dann über das andere Array iteriert wird. In jeder Iteration shiftwird verwendet, um das vorderste Element der Liste der Positionsparameter zu verschieben.

verwandte Informationen