Menggabungkan dua variabel dengan garis bawah


54

Saya perlu menggabungkan dua variabel untuk membuat nama file yang memiliki garis bawah. Mari kita memanggil variabel saya $FILENAMEdan di $EXTENSIONmana nama file dibaca dari file.

FILENAME=Hello
EXTENSION=WORLD.txt

Sekarang...

Saya telah mencoba yang berikut ini tanpa hasil:

NAME=${FILENAME}_$EXTENSION
NAME=${FILENAME}'_'$EXTENSION
NAME=$FILENAME\\_$EXTENSION

Saya selalu mendapatkan semacam hasil aneh. Biasanya garis bawah dulu.

Saya membutuhkannya

echo $NAME
Hello_WORLD.txt

2
Mungkin skrip Anda berisi karakter carriage return.
Stéphane Chazelas

Ya itu saja. : D
Rhyuk

Jawaban:


67

Anda dapat menggunakan sesuatu seperti ini:

NAME=$(echo ${FILENAME}_${EXTENSION})

Ini juga berfungsi:

NAME=${FILENAME}_${EXTENSION}

1
Masalahnya adalah file tempat saya membaca NAMA. Pemformatan Windows ... Solusi Anda bekerja sangat baik setelah itu. Terima kasih
Rhyuk

2
Perintah pertama menguraikan nilai variabel dan penggunaan substitusi perintah dan echotidak mungkin bisa membantu. Perintah kedua sudah diberikan dalam pertanyaan.
Gilles 'SANGAT berhenti menjadi jahat'

1
Iya! Aku menyukainya. Ini sangat mengganggu saya untuk waktu yang lama. Terima kasih atas solusinya!
racl101

Ini bekerja untuk saya. Ketika saya menggunakan '$ FILENAME_ $ EXTENSION', hanya nilai '$ EXTENSION' yang muncul. Bisakah Anda membantu menjelaskan mengapa ini terjadi? Terima kasih
Lei Hao

12

Anda:

NAME=${FILENAME}_$EXTENSION
NAME=${FILENAME}'_'$EXTENSION

semuanya baik-baik saja, jadi akan:

NAME=${FILENAME}_${EXTENSION}
NAME=$FILENAME'_'$EXTENSION
NAME=$FILENAME\_$EXTENSION
NAME=$FILENAME"_$EXTENSION"

(tetapi tentu tidak NAME=$(echo ${FILENAME}_${EXTENSION}) seperti itu menggunakanecho dan yang split+globoperator yang ).

NAME=$FILENAME_$EXTENSION

akan sama dengan:

NAME=${FILENAME_}${EXTENSION}

as _(bertentangan dengan \atau ') adalah karakter yang valid dalam nama variabel.

Masalah Anda adalah bahwa Anda memiliki garis yang dibatasi dengan CRLF dan bukan hanya LF, yang berarti bahwa konten variabel tersebut berakhir dengan karakter CR.

Karakter CR, ketika ditulis ke terminal memberitahu terminal untuk memindahkan kursor ke awal baris. Jadi Hello<CR>_WORLD.TXT<CR>ketika dikirim ke terminal akan ditampilkan sebagai _WORLD.TXT(menimpa Hello).


1

Saya sudah beralih menggunakan ${FILENAME}_${EXTENSION}sintaks yang disebutkan di atas.

Saya biasa menggunakan $()ketika saya harus menggabungkan dua variabel dengan garis bawah. Misalnya, $YYYYMMDD$()_$HHMMSSuntuk menghasilkan nama file yang berisi stempel waktu dalam format YYYYMMDD_HHMMSS. Bagian tengah $()tidak menghasilkan apa-apa dan memecah dua variabel secara terpisah.

Saya biasa timemengukur tugas menggunakan $YYYYMMDD$()_$HHMMSSmetode dan beberapa di atas, dan mereka semua melaporkan 0ms di server lama saya menggunakan ini. Kinerja sepertinya tidak menjadi masalah.


Itu tidak menjawab pertanyaan. Anda harus mengajukan pertanyaan baru untuk itu. $()tidak garpu subkulit dalam beberapa shell (beberapa mengoptimalkannya). Ini juga membajak operator untuk sesuatu yang tidak dirancang untuknya. ${x}_yadalah apa yang kamu inginkan.
Stéphane Chazelas

Apa maksudmu, “Itu tidak menjawab pertanyaan.”? Itu bukan jawaban yang bagus, tetapi itu adalah jawaban.
Scott

Diedit untuk menghapus ambiguitas.
user208145

0

Anda harus menggunakan variabel dalam huruf kecil (ini adalah praktik terbaik).
Jadi, saya akan menggunakan nama file dan ekstensi sebagai ganti FILENAME dan EXTENSION

Seperti yang Anda katakan bahwa "nama file dibaca dari file", saya akan menganggap bahwa skripnya adalah:

read -r filename  <file.txt
extension=World.txt

Dan Anda ingin menggabungkan kedua variabel $ nama file dan $ ekstensi dengan garis bawah _.
Contoh yang Anda berikan (kecuali: tidak ada dobel \) berfungsi dengan benar di sini:

name=${filename}_$extension
name=${filename}'_'$extension
name=$filename\_$extension

Seperti beberapa lainnya:

name="${filename}"'_'"${extension}"
name="$filename"'_'"$extension"
name="${filename}_${extension}"

Jadi, masalah Anda bukan dengan bagaimana variabel tetap bersatu, tetapi dengan isi vars. Tampaknya masuk akal untuk berpikir bahwa ini:

read -r filename  <file.txt

akan membaca carriage carriage return \rjika membaca dari file windows.

Salah satu solusi sederhana (untuk ksh, bash, zsh) adalah menghapus semua karakter kontrol dari variabel baca:

filename=${filename//[[:cntrl:]]/}

Ini bisa disimulasikan dengan nilai yang memiliki carriage return:

$ filename=$'Hello\r'
$ echo "starting<$filename>end"
>endting<Hello                       ### note the return to the start of line.
$ echo "starting<${filename//[[:cntrl:]]/}>end"
starting<Hello>end

Atau, mengganti nilai filename:

$ filename="${filename//[[:cntrl:]]/}"
$ echo "start<$filename>end"
start<Hello>end

Kesimpulan.

Jadi ini:

name="${filename//[[:cntrl:]]/}_${extension//[[:cntrl:]]/}"

Akan mendapatkan nilai yang benar namebahkan jika vars lain berisi karakter kontrol.



-2

Anda juga dapat menggunakan ini: pisahkan vars terpisah dengan spasi dan gabungkan mereka menggunakan tr untuk menghapus ruang.

TableNameToCreate="MyTable"
# concatenation work is done here 
$(echo "$TableNameToCreate _my_other_Info " | tr -d " ")

#Proof
echo "Var to create with var pasted as prefix to suffix
    $(echo "$TableNameToCreate _my_other_Info " | tr -d " ") 
. "

# create a new var
NewVar=$(echo "$TableNameToCreate _my_other_Info " | tr -d " ")

#proof
echo "$NewVar"

(1) Pertanyaan ini sudah dijawab lebih dari cukup. (2) Apa jawaban Anda jika variabel yang ada memiliki karakter khusus di dalamnya?
G-Man Mengatakan 'Reinstate Monica'

Ini tidak mengatasi masalah dengan variabel yang berisi carriage return. Ini juga menghilangkan spasi, sesuatu yang mungkin tidak diinginkan.
Kusalananda

@ Kusalananda: Sebenarnya, kecuali saya menghadap sesuatu, ini menangani pengangkutan kembali dengan baik; ruang adalah satu-satunya masalah.
G-Man Mengatakan 'Reinstate Monica'
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.