Mengganti beberapa karakter dalam string dengan karakter lain

279

Saya memiliki string seperti AxxBCyyyDEFzzLMN dan saya ingin mengganti semua kemunculan x , y , dan z dengan _ .

Bagaimana saya bisa mencapai ini?

Saya tahu itu echo "$string" | tr 'x' '_' | tr 'y' '_'akan berhasil, tetapi saya ingin melakukannya dalam sekali jalan, tanpa menggunakan pipa.

Amarsh
sumber
Apakah Anda ingin mengganti urutan x, y, atau z berturut-turut dengan satu garis bawah, atau apakah Anda ingin mengganti setiap x, y, atau z dengan satu garis bawah? Juga, bagaimana dengan urutan campuran, seperti AxyzB? Tiga garis bawah atau satu?
David Z
tr '[xyz]'akan menggantikan [dan ]juga. Argumennya harus berupa daftar karakter (meskipun rentang seperti a-zboleh saja, dan dalam beberapa implementasi, kelas karakter POSIX suka [:digit:]).
tripleee

Jawaban:

329
echo "$string" | tr xyz _

akan mengganti setiap terjadinya x, yatau zdengan _, memberikan A__BC___DEF__LMNdalam contoh Anda.

echo "$string" | sed -r 's/[xyz]+/_/g'

akan menggantikan kejadian berulang x, yatau zdengan tunggal _, memberikan A_BC_DEF_LMNdalam contoh Anda.

jkasnicki
sumber
19
Di Mac, saya mendapatkan yang berikut: sed: opsi ilegal - penggunaan r: sed script [-Ealn] [-i extension] [file ...] sed [-Ealn] [-i extension] [-i script]. .. [-f script_file] ... [file ...]
catanore
Saya memiliki string yang berisi ,[]{}()~karakter. Saya ingin menggantinya dengan setiap karakter khusus lolos dengan '\'bagaimana saya bisa menyelesaikan ini dengan oneshot?
inckka
2
@halakala Mac dikirimkan dengan versi sed yang sedikit berbeda. Lihat pertanyaan ini: unix.stackexchange.com/questions/13711/... Alih-alih, Anda dapat menginstal "gnu-sed" dengan manajer paket Homebrew lalu gunakan gsedbinary: $ brew install gnu-sedthen$ gsed -r 's/[xyz]+/_/g'
John Kary
6
Pada * BSD (dan karenanya, OSX), sed -Epada dasarnya setara dengan sed -rpada banyak distro Linux, Jika Anda menggunakan, sed 's/[xyz][xyz]*/_/g'Anda tidak memerlukan opsi. Tentu saja, ini setara dengan tr -s xyz _jadi tidak perlu di sedsini.
tripleee
@inckka Anda tidak dapat menggunakannya truntuk itu. sed 's/[][{}()~,]/\\&/g'tapi sungguh, ajukan pertanyaan baru jika Anda memiliki pertanyaan lanjutan (silakan tautkan kembali ke sini untuk referensi, tentu saja). Kebetulan, ,dan ~bukan regex metacharacters (meskipun ~akan diperluas ke $HOMEdalam beberapa posisi oleh Bash dan beberapa shell lainnya; shnamun tidak ).
tripleee
286

Menggunakan Bash Parameter Expansion :

orig="AxxBCyyyDEFzzLMN"
mod=${orig//[xyz]/_}
Matthew Flaschen
sumber
7
Substitusi buruk
Alexey
1
@ Alexey, contoh saya bekerja untuk saya (bash 4.3.11 (1) -release). Pastikan Anda menggunakan bash. Kerang lain mungkin tidak berfungsi (meskipun beberapa akan).
Matthew Flaschen
@MatthewFlaschen terima kasih. Ini adalah persis apa yang saya perlu lakukan untuk mengganti path absolut dalam skrip bash (mengganti / dengan \ / jadi sed menerimanya).
Ryan G
1
@RyanG mengapa digunakan sedjika bash memiliki subtitusi bawaan ?
MestreLion
@MestreLion Itu mungkin salah, tapi saya perlu mengganti nama variabel standar dalam banyak file dengan path absolut, yang saya gunakan sebagai pengganti in-house. tetapi Anda tidak dapat memiliki "/" tanpa menghindarinya dalam perintah. Saya merangkai operasi bersama dalam bash. Apakah ini bukan cara terbaik untuk memanipulasi string dalam bash?
Ryan G
111

Anda mungkin menemukan tautan ini bermanfaat:

http://tldp.org/LDP/abs/html/string-manipulation.html

Secara umum,

Untuk mengganti kecocokan pertama dari $ substring dengan $ replacement:

${string/substring/replacement}

Untuk mengganti semua kecocokan $ substring dengan $ replacement:

${string//substring/replacement}

EDIT: Perhatikan bahwa ini berlaku untuk variabel bernama $ string.

Dylan Daniels
sumber
16
Perhatikan bahwa ini berfungsi pada variabel bernama "string" bukan pada string literal.
mattdm
1
paling bermanfaat, karena mengandung referensi.
Os3
Solusi terbaik dan terpendek.
northtree
8
read filename ;
sed -i 's/letter/newletter/g' "$filename" #letter

^ gunakan sebanyak mungkin yang Anda butuhkan, dan Anda dapat membuat enkripsi BASIC Anda sendiri

Michael
sumber
5

Berikut ini adalah solusi dengan ekspansi parameter shell yang menggantikan beberapa kejadian yang berdekatan dengan satu _:

$ var=AxxBCyyyDEFzzLMN
$ echo "${var//+([xyz])/_}"
A_BC_DEF_LMN

Perhatikan bahwa polanya memerlukan pencocokan pola yang diperluas, diaktifkan dengan+(pattern)

shopt -s extglob

Atau, dengan opsi -s("pemerasan") dari tr:

$ tr -s xyz _ <<< "$var"
A_BC_DEF_LMN
Benjamin W.
sumber