Înlocuirea caracterelor speciale într-un script shell folosind sed (Programare, Shell, Sed, Sh)

user3074091 a intrebat.
a intrebat.

Încerc să scriu un script de shell care va înlocui orice caractere / șiruri pe care le aleg folosind sed. Prima mea încercare a funcționat cu excepția caracterelor speciale. Am încercat să folosesc sed pentru a repara caracterele speciale astfel încât și acestea să fie căutate sau înlocuite. Am decis să simplific scriptul în scop de testare și să mă ocup doar de un singur caracter incriminat. Cu toate acestea, încă mai am probleme.

Script editat

#! /bin/sh
oldString=$1
newString=$2
file=$3

oldStringFixed=$(echo "$oldString" | sed 's/\/\\/g')
oldStringFixed=$(echo "$oldStringFixed" | sed 's/[/\[/g')
oldStringFixed=$(echo "$oldStringFixed" | sed 's/]/\]/g')
oldStringFixed=$(echo "$oldStringFixed" | sed 's/^/\^/g')
oldStringFixed=$(echo "$oldStringFixed" | sed 's/*/\*/g')
oldStringFixed=$(echo "$oldStringFixed" | sed 's/+/\+/g')
oldStringFixed=$(echo "$oldStringFixed" | sed 's/./\./g')
oldStringFixed=$(echo "$oldStringFixed" | sed 's/$/\$/g')
oldStringFixed=$(echo "$oldStringFixed" | sed 's/-/\-/g')

sed -e "s/$oldStringFixed/$newString/g" "$file" > newfile.updated
mv newfile.updated "$file"#! /bin/sh

În cazul în care nu este clar, încerc să caut în oldString caracterul [, să îl înlocuiesc cu o versiune scăpată și să atribui rezultatele la oldStringFixed (am nevoie de ghilimele pentru asta?). Cele două linii de jos sunt versiuni ușor modificate ale scriptului meu original care cred că funcționează corect.

Când dau un ecou la șirul fixat, nu se afișează nimic, iar sed emite o eroare

sed: can't read [: No such file or directory

Poate cineva să explice ce este în neregulă cu prima mea linie sed?

EDIT:

Mulțumită lui Jite, scriptul funcționează mai bine. Cu toate acestea, am încă o problemă cu înlocuirea caracterelor între ghilimele simple cu spații, de exemplu ‘ *’. Noua versiune este cea de mai sus.

Comentarii

  • există mult mai multe caractere specias decât „[„, cum ar fi . * + ? pentru OldString și & / pentru newString –  > Por NeronLeVelu.
  • Destul de asemănător cu această întrebare. –  > Por devnull.
4 răspunsuri
Spectacolul care nu se termină niciodată

Vă sugerez două îmbunătățiri:

  1. Nu stivuiți apelurile către sed așa cum faceți, în schimb împachetați-le pe toate într-o singură funcție, ca escape_string mai jos.

  2. Puteți folosi un delimitator fantezist pentru sed comandă de substituire pentru a evita problemele legate de / fiind parte a șirurilor de caractere implicate.

Cu aceste modificări, scriptul dvs. arată astfel:

#! /bin/sh
oldString="$1"
newString="$2"
file="$3"

escape_string()
{
   printf '%s' "$1" | sed -e 's/[][\^*+.$-]/\1/g'
}

fancyDelim=$(printf '01')

oldStringFixed=$(escape_string "$oldString")
sed -e "s$fancyDelim$oldStringFixed$fancyDelim$newString${fancyDelim}g" "$file" 
  > newfile.updated
mv newfile.updated "$file"

Comentarii

  • Puteți generaliza cu ușurință la s/[][\^*+.$-]/\1/g (și nu sunt sigur de ce doriți să includeți cratima, așa că vă sugerez să o scoateți). –  > Por tripleee.
  • Minunat, am adăugat modificările tale! –  > Por Spectacolul care nu se termină niciodată.
  • La mine nu funcționează, îmi apare „sed: -e expresia #1, char 21: referință invalidă 1 pe RHS a comenzii `s'” –  > Por Ben Farmer.
Jite

Schimbare:

oldStringFixed= `sed 's/[/[/g' "$oldString"`

în:

oldStringFixed=$(echo "$oldString" | sed 's/[/\[/g')

Problema 1: Spațiu după =, , nu este permis atunci când se atribuie variabile de shell.

Problema 2: sed se așteaptă ca intrarea să fie un fișier, nu un șir de caractere. Totuși, puteți să o introduceți în pipe, așa cum face soluția mea.

Problema 3: trebuie să scăpați mai întâi backslash-ul. \, , apoi trebuie să scăpați caracterul [, , totalizând \[ 🙂

Notă laterală: Am schimbat „ în $() deoarece aceasta din urmă este praxisul recomandat (din cauza cuibării, un alt subiect).

Comentarii

  • Mulțumesc pentru ajutor. Modificările dvs. funcționează foarte bine și am adăugat declarații sed suplimentare pentru a face față altor caractere problematice. Cu toate acestea, atunci când încerc să înlocuiesc un singur caracter citat cu un spațiu, cum ar fi ‘ *’, rezultatul este incorect. Se poate repara acest lucru? –  > Por user3074091.
  • Totul poate fi reparat. Sincer, pentru acest caz, eu aș scrie un fișier sed.script care să conțină toate comenzile care urmează să fie executate, câte una pe linie, și apoi să folosesc sed -f sed.script doar o singură dată, în loc să reinvocați sed de mai multe ori. Acest lucru înseamnă, de asemenea, că nu trebuie să scăpați scriptul față de shell – vă face viața mai ușoară. –  > Por Jonathan Leffler.
  • @user3074091 Nu înțeleg întrebarea ta. Vă rugăm să vă actualizați întrebarea cu un exemplu de intrare și ce ieșire vă așteptați, sperăm să putem veni cu un răspuns. –  > Por Jite.
Sushant Dhingra

Către înlocuirea valorilor care conțin caractere speciale încercați să utilizați sed cu „|” în loc de „/”

De exemplu: sed -i ‘s||’$valoare_originală’|’$valoare_nouă’|g’

unde original_value=”comprising_special_char_char_/”new_value=”comprising_new_special_char:”

Ben Farmer

Pentru mine a fost un coșmar să încerc să fac sed să facă acest lucru pentru cazul general. Am renunțat și am scris un scurt cod Python pentru a înlocui sed:

#!/usr/bin/python
# replace.py
import sys

# Replace string in a file (in place)
match=sys.argv[1]
replace=sys.argv[2]
filename=sys.argv[3]

print "Replacing strings in",filename

with open(filename,"r") as f:
  data = f.read().replace(match,replace)

with open(filename,"w") as f:
  f.write(data)

Care poate fi apoi utilizat ca:

#!/bin/bash
orig='<somethinghorrible>'
out='<replacement>'
python replace.py "$orig" "$out" myfile.txt

Tags:, ,