1

When using Bash I want to WGET multiple files from a server so I write a script with a For-loop that increments a counter to match the numbering of the files.

But I want to include the title of the file AND the number in which order the file appears (the "ID" of the file). So the the file has a URI of "example.com/files/hello_world.txt", with the ID of 42 and the title is "Hello World" when WGET it, the downloaded file should have the name "42_Hello_World.txt".

I tried the following code:

#! /bin/bash

# Init
index=42
title="Hello World"

# Replace blanks with underscore
title=${title/ /_}

# Concat fileName
fileName="$index_$title.txt"
echo $fileName

but the output is just "Hello_World.txt". When I change the order of $title and $index the output is "42.txt"

Can someone explain to me why this happens and how to solve it?

tl;dr When using two or more variables in bash when evaluating a string only the last variable is "expanded". The first one is ignored. WHY???

Radinator
  • 1,048
  • 18
  • 58
  • 1
    Your tl;dr misidentifies the problem; both variables *are* expanded, but the first expansion isn't using the name you think it is. – chepner Sep 04 '19 at 13:11

4 Answers4

2

_ is a valid character for an identifier, so $index_$title.txt is interpreted as the concatenation of two parameter expansions, $index_ and $title. To explicitly delimit the parameter name, use the full ${...} form:

fileName=${index}_$title.txt

The braces are not necessary for $title, because the following . cannot be interpreted as part of a parameter name (though the braces are certainly permitted: ${index}_${title}.txt).

Since index_ is not defined, $index_ expands to the empty string.

chepner
  • 497,756
  • 71
  • 530
  • 681
2

Yes. The explanation is the the _ character is a valid character in a variable name, so that your expressions are expanding the (undefined) variables $index_ and $title_ as empty strings. (The . is not a valid name character, so it terminates the 2nd name automatically.) Do this instead:

$ fileName="${index}_$title.txt"
$ echo $fileName
42_Hello_World.txt
$ echo "${title}_$index.txt"
Hello_World_42.txt
Jeff Y
  • 2,437
  • 1
  • 11
  • 18
1

Could you please try following. This change should provide you your expected results. It is simple your variable "$index_$title.txt" is considered as you are concatenating 2 variables (index_ and title) so its better to quote _ like --> "_" and tell shell that it is a string.

index="42"
str="Hello World"
# Replace blanks with underscore
title=${str/ /_}
# Concat fileName
fileName=$index"_"$title".txt"
echo $fileName

In this nice url, you could see the last example of VALID variables(_ is there in the list):

https://bash.cyberciti.biz/guide/Rules_for_Naming_variable_name

RavinderSingh13
  • 130,504
  • 14
  • 57
  • 93
0

The _ in the filename is not helping. _ is a valid variable character, and bash thinks that you want a variable called $index_ followed by $title, which isn't what you want. You can either:

  1. Change the underscore character to an invalid variable name
  2. Change to filename=$title"_"$index".txt" or
  3. put brackets around $index

Hope this helps!

EDIT: You already have an answer here! How to echo "$x_$y" in Bash script?