Ganti string dalam skrip shell menggunakan variabel

94

Saya menggunakan kode di bawah ini untuk mengganti string di dalam skrip shell.

echo $LINE | sed -e 's/12345678/"$replace"/g'

tetapi diganti dengan $replacealih - alih nilai variabel itu.

Adakah yang bisa tahu apa yang salah?

Vijay
sumber
Untuk pertanyaan umum terkait tentang menangani nilai dengan garis miring di dalamnya, lihat stackoverflow.com/questions/5864146/use-slashes-in-sed-replace
tripleee

Jawaban:

147

Jika Anda ingin menafsirkan $replace, Anda tidak boleh menggunakan tanda kutip tunggal karena mereka mencegah substitusi variabel.

Mencoba:

echo $LINE | sed -e "s/12345678/\"${replace}\"/g"

dengan asumsi Anda ingin kutipan dimasukkan. Jika Anda tidak menginginkan kutipan, gunakan:

echo $LINE | sed -e "s/12345678/${replace}/g"

Salinan:

pax> export replace=987654321
pax> echo X123456789X | sed "s/123456789/${replace}/"
X987654321X
pax> _

Berhati-hatilah untuk memastikan bahwa ${replace}tidak ada karakter yang penting sed(seperti /misalnya) karena akan menyebabkan kebingungan kecuali lolos. Tetapi jika, seperti yang Anda katakan, Anda mengganti satu nomor dengan yang lain, itu seharusnya tidak menjadi masalah.

paxdiablo
sumber
saya tidak ingin kutipan dimasukkan. saya ingin satu nomor diganti dengan yang lain
Vijay
1
paxdiablo: setjuga tidak perlu (dan bagaimana Anda akan menggunakannya?). Cuma replace=987654321.
Roman Cheplyaka
Saya biasanya selalu menggunakan exportuntuk memastikan bahwa variabel ditetapkan untuk anak-anak tetapi, seperti yang Anda katakan, Anda dapat dengan mudah menghindarinya. Namun, penggunaan atau tidak dari exporttidak relevan di sini (masalah gaya) dan tidak berpengaruh pada jawaban sebenarnya, yaitu bagaimana menggunakan variabel dalam sedperintah.
paxdiablo
Solusi ini tampaknya tidak berfungsi dengan -iopsi tersebut. Tahukah kamu mengapa? atau bagaimana cara membuatnya bekerja?
Gabriel
1
Mungkin juga menunjukkan bahwa beralih dari tanda kutip tunggal ke ganda memerlukan salah satu $atau `dalam sedskrip untuk di-escape dengan garis miring terbalik, untuk melindunginya dari mekanisme substitusi shell untuk string yang dikutip ganda.
tripleee
74

Anda bisa menggunakan shell (bash / ksh).

$ var="12345678abc"
$ replace="test"
$ echo ${var//12345678/$replace}
testabc
anjing hantu74
sumber
3
Mungkin ingin menyebutkan itu khusus bash (dan ksh?). Mungkin tidak diimpor ke kebanyakan orang tetapi beberapa dari kita masih dipaksa untuk mengerjakan UNIXen kuno :-)
paxdiablo
6
Hati-hati, ini juga gagal pada dasbor, yang ada /bin/shdi banyak Linux modern.
phihag
28

Tidak spesifik untuk pertanyaan tersebut, tetapi untuk orang-orang yang membutuhkan jenis fungsionalitas yang sama yang diperluas untuk kejelasan dari jawaban sebelumnya:

# create some variables
str="someFileName.foo"
find=".foo"
replace=".bar"
# notice the the str isn't prefixed with $
#    this is just how this feature works :/
result=${str//$find/$replace}
echo $result    
# result is: someFileName.bar

str="someFileName.sally"
find=".foo"
replace=".bar"
result=${str//$find/$replace}
echo $result    
# result is: someFileName.sally because ".foo" was not found
bob
sumber
10

Menemukan solusi yang anggun .

echo ${LINE//12345678/$replace}
Nicolae Iotu
sumber
8

Tanda kutip tunggal sangat kuat. Begitu masuk, tidak ada yang dapat Anda lakukan untuk memanggil substitusi variabel, sampai Anda pergi. Gunakan tanda kutip ganda sebagai gantinya:

echo $LINE | sed -e "s/12345678/$replace/g"
Dave
sumber
4
echo $LINE | sed -e 's/12345678/'$replace'/g'

Anda masih dapat menggunakan tanda kutip tunggal, tetapi Anda harus "membukanya" jika ingin variabel diperluas di tempat yang tepat. jika tidak, string akan diambil "secara harfiah" (seperti @paxdiablo dinyatakan dengan benar, jawabannya juga benar)

akira
sumber
Ini memiliki masalah bahwa menggunakan di $replaceluar tanda kutip apa pun akan menyebabkan shell melakukan tokenisasi spasi putih dan perluasan karakter pengganti pada nilainya. Ini akan tampak bekerja dengan nilai-nilai sederhana, tetapi bisa meledak secara dramatis pada string nontrivial. Jangan gunakan ini dalam kode produksi.
tripleee
2

Untuk membiarkan shell Anda memperluas variabel, Anda perlu menggunakan tanda kutip ganda seperti

sed -i "s#12345678#$replace#g" file.txt

Ini akan rusak jika $replaceberisi sedkarakter khusus ( #, \). Tetapi Anda dapat melakukan praproses $replaceuntuk mengutipnya:

replace_quoted=$(printf '%s' "$replace" | sed 's/[#\]/\\\0/g')
sed -i "s#12345678#$replace_quoted#g" file.txt
Matthieu Moy
sumber
0

Saya memiliki persyaratan yang mirip dengan ini tetapi var pengganti saya mengandung ampersand. Melarikan diri dari ampers dan seperti ini memecahkan masalah saya:

replace="salt & pepper"
echo "pass the salt" | sed "s/salt/${replace/&/\&}/g"
Richard Salt
sumber
-1

Gunakan ini sebagai gantinya

echo $LINE | sed -e 's/12345678/$replace/g'

ini berfungsi untuk saya, cukup hapus tanda kutip

Tunde Pizzle
sumber
-2

Saya lebih suka menggunakan tanda kutip ganda, karena quptes tunggal sangat kuat karena kami menggunakannya jika tidak dapat mengubah apa pun di dalamnya atau dapat memanggil penggantian variabel.

jadi gunakan tanda kutip ganda.

echo $LINE | sed -e "s/12345678/$replace/g"
SteveScm
sumber
6
Apakah ini berbeda dengan jawaban Dave ?
devnull