Powinieneś używać zmiennych małymi literami (jest to najlepsza praktyka).
Więc użyję nazwy pliku i rozszerzenia zamiast FILENAME i EXTENSION
Mówiąc, że „nazwa pliku jest odczytywana z pliku”, zakładam, że skrypt to:
read -r filename <file.txt
extension=World.txt
I że chcesz połączyć obie zmienne $ filename i $ extension z podkreśleniem _
.
Podane przykłady (z wyjątkiem: brak podwójnego \) działają tutaj poprawnie:
name=${filename}_$extension
name=${filename}'_'$extension
name=$filename\_$extension
Jak niektóre inne:
name="${filename}"'_'"${extension}"
name="$filename"'_'"$extension"
name="${filename}_${extension}"
Twój problem nie polega na tym, jak zmienne są sklejone, ale na zawartości zmiennych. Wydaje się rozsądne sądzić, że to:
read -r filename <file.txt
odczyta końcowy powrót karetki, \r
jeśli będzie czytać z pliku Windows.
Jednym prostym rozwiązaniem (dla ksh, bash, zsh) jest usunięcie wszystkich znaków kontrolnych ze zmiennej read:
filename=${filename//[[:cntrl:]]/}
Można to zasymulować za pomocą wartości, która ma znak powrotu karetki:
$ 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
Lub zastępując wartość filename
:
$ filename="${filename//[[:cntrl:]]/}"
$ echo "start<$filename>end"
start<Hello>end
Wniosek.
Więc to:
name="${filename//[[:cntrl:]]/}_${extension//[[:cntrl:]]/}"
Otrzyma poprawną wartość, name
nawet jeśli inne zmienne zawierają znaki kontrolne.