Saya mencoba mencari cara untuk membuat bash (force?) Memperluas variabel dalam string (yang dimuat dari file).
Saya memiliki file bernama "sesuatu.txt" dengan konten:
hello $FOO world
Saya kemudian lari
export FOO=42
echo $(cat something.txt)
ini mengembalikan:
hello $FOO world
Itu tidak memperluas $ FOO meskipun variabel telah ditetapkan. Saya tidak dapat mengevaluasi atau mencari file - karena akan mencoba dan mengeksekusinya (tidak dapat dieksekusi apa adanya - saya hanya ingin string dengan variabel diinterpolasi).
Ada ide?
eval
.eval
dan penting untuk menyadari implikasinya.Jawaban:
Saya tersandung pada apa yang menurut saya adalah jawaban ATAS pertanyaan ini:
envsubst
perintah.Jika itu belum tersedia di distro Anda, itu ada di
Paket GNU
gettext
.@Rockallite - Saya menulis skrip pembungkus kecil untuk mengatasi masalah '\ $'.
(BTW, ada "fitur" dari envsubst, dijelaskan di https://unix.stackexchange.com/a/294400/7088 untuk memperluas hanya beberapa variabel dalam masukan, tetapi saya setuju bahwa keluar dari pengecualian jauh lebih banyak mudah.)
Ini skrip saya:
#! /bin/bash ## -*-Shell-Script-*- CmdName=${0##*/} Usage="usage: $CmdName runs envsubst, but allows '\$' to keep variables from being expanded. With option -sl '\$' keeps the back-slash. Default is to replace '\$' with '$' " if [[ $1 = -h ]] ;then echo -e >&2 "$Usage" ; exit 1 ;fi if [[ $1 = -sl ]] ;then sl='\' ; shift ;fi sed 's/\\\$/\${EnVsUbDolR}/g' | EnVsUbDolR=$sl\$ envsubst "$@"
sumber
$
pelolosan tanda dolar ( ), misalnyaecho '\$USER' | envsubst
akan menampilkan nama pengguna saat ini dengan garis miring ke belakang, bukan$USER
.brew link --force gettext
Banyak jawaban yang menggunakan
eval
danecho
jenis pekerjaan, tetapi merusak berbagai hal, seperti beberapa baris, mencoba untuk keluar dari meta-karakter shell, melarikan diri di dalam template yang tidak dimaksudkan untuk diperluas oleh bash, dll.Saya memiliki masalah yang sama, dan menulis fungsi shell ini, yang sejauh yang saya tahu, menangani semuanya dengan benar. Ini masih akan menghapus hanya baris baru dari template, karena aturan substitusi perintah bash, tetapi saya tidak pernah menemukan itu menjadi masalah selama yang lainnya tetap utuh.
apply_shell_expansion() { declare file="$1" declare data=$(< "$file") declare delimiter="__apply_shell_expansion_delimiter__" declare command="cat <<$delimiter"$'\n'"$data"$'\n'"$delimiter" eval "$command" }
Misalnya, Anda dapat menggunakannya seperti ini dengan
parameters.cfg
yang merupakan skrip shell yang hanya menetapkan variabel, dantemplate.txt
template yang menggunakan variabel tersebut:. parameters.cfg printf "%s\n" "$(apply_shell_expansion template.txt)" > result.txt
Dalam praktiknya, saya menggunakan ini sebagai semacam sistem template ringan.
sumber
eval
jebakan yang biasa . Coba tambahkan; $(eval date)
di akhir baris mana pun di dalam file input dan itu akan menjalankandate
perintah.Anda dapat mencoba
echo $(eval echo $(cat something.txt))
sumber
echo -e "$(eval "echo -e \"`<something.txt`\"")"
jika Anda membutuhkan baris baru.template.txt
adalah teks. Operasi ini berbahaya karena menjalankan (mengevaluasi) perintah jika ada.Anda tidak ingin mencetak setiap baris, Anda ingin mengevaluasinya sehingga Bash dapat melakukan substitusi variabel.
FOO=42 while read; do eval echo "$REPLY" done < something.txt
Lihat
help eval
atau manual Bash untuk informasi lebih lanjut.sumber
eval
berbahaya ; Anda tidak hanya$varname
berkembang (seperti yang Anda lakukan denganenvsubst
), tetapi$(rm -rf ~)
juga.Pendekatan lain (yang tampaknya menjijikkan, tetapi saya tetap meletakkannya di sini):
Tulis konten sesuatu.txt ke file temp, dengan pernyataan echo yang membungkusnya:
something=$(cat something.txt) echo "echo \"" > temp.out echo "$something" >> temp.out echo "\"" >> temp.out
lalu masukkan kembali ke variabel:
RESULT=$(source temp.out)
dan $ RESULT akan membuat semuanya diperluas. Tapi sepertinya salah!
sumber
Jika Anda hanya ingin referensi variabel diperluas (tujuan yang saya miliki untuk saya sendiri), Anda dapat melakukan hal di bawah ini.
contents="$(cat something.txt)" echo $(eval echo \"$contents\")
(Kutipan yang lolos di sekitar $ konten adalah kuncinya di sini)
sumber
eval "echo \"$$contents\""
dan itu mempertahankan spasiJika sesuatu.txt hanya memiliki satu baris,
bash
metode, (versi yang lebih pendek dari jawaban "icky" Michael Neale ), menggunakan substitusi proses & perintah :FOO=42 . <(echo -e echo $(<something.txt))
Keluaran:
Perhatikan bahwa
export
itu tidak diperlukan.Jika something.txt memiliki satu atau lebih garis, GNU valuate metode:
sed
e
FOO=42 sed 's/"/\\\"/g;s/.*/echo "&"/e' something.txt
sumber
sed
evaluasi yang paling sesuai dengan tujuan saya. Saya perlu membuat skrip dari template, yang nilainya diisi dari variabel yang diekspor ke file konfigurasi lain. Ini menangani pelolosan dengan benar untuk perluasan perintah misalnya dimasukkan ke\$(date)
dalam template untuk mendapatkan$(date)
output. Terima kasih!Solusi berikut:
memungkinkan penggantian variabel yang ditentukan
meninggalkan placeholder variabel yang tidak berubah yang tidak ditentukan. Ini sangat berguna selama penerapan otomatis.
mendukung penggantian variabel dalam format berikut:
${var_NAME}
$var_NAME
melaporkan variabel mana yang tidak didefinisikan dalam lingkungan dan mengembalikan kode kesalahan untuk kasus seperti itu
TARGET_FILE=someFile.txt; ERR_CNT=0; for VARNAME in $(grep -P -o -e '\$[\{]?(\w+)*[\}]?' ${TARGET_FILE} | sort -u); do VAR_VALUE=${!VARNAME}; VARNAME2=$(echo $VARNAME| sed -e 's|^\${||g' -e 's|}$||g' -e 's|^\$||g' ); VAR_VALUE2=${!VARNAME2}; if [ "xxx" = "xxx$VAR_VALUE2" ]; then echo "$VARNAME is undefined "; ERR_CNT=$((ERR_CNT+1)); else echo "replacing $VARNAME with $VAR_VALUE2" ; sed -i "s|$VARNAME|$VAR_VALUE2|g" ${TARGET_FILE}; fi done if [ ${ERR_CNT} -gt 0 ]; then echo "Found $ERR_CNT undefined environment variables"; exit 1 fi
sumber
$ eval echo $(cat something.txt) hello 42 world $ bash --version GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin17) Copyright (C) 2007 Free Software Foundation, Inc.
sumber
foo=45 file=something.txt # in a file is written: Hello $foo world! eval echo $(cat $file)
sumber
envsubst
adalah solusi yang bagus (lihat jawaban LenW) jika konten yang Anda gantikan memiliki panjang yang "masuk akal".Dalam kasus saya, saya perlu mengganti konten file untuk mengganti nama variabel.
envsubst
mengharuskan konten diekspor sebagai variabel lingkungan dan bash mengalami masalah saat mengekspor variabel lingkungan yang lebih dari satu megabyte atau lebih.solusi awk
Menggunakan solusi cuonglm dari pertanyaan berbeda:
needle="doc1_base64" # The "variable name" in the file. (A $ is not needed.) needle_file="doc1_base64.txt" # Will be substituted for the needle haystack=$requestfile1 # File containing the needle out=$requestfile2 awk "BEGIN{getline l < \"${needle_file}\"}/${needle}/{gsub(\"${needle}\",l)}1" $haystack > $out
Solusi ini berfungsi bahkan untuk file besar.
sumber
Karya-karya berikut:
bash -c "echo \"$(cat something.txt)"\"
sumber
$foo
, tetapi yang tidak aman seperti$(rm -rf ~)
.