I want to extract part of string in a variable as below, but it returned bad substitution.

for i in `ls`;do echo ${i|cut -d. -f1};done

-bash: ${i|cut -d. -f1}: bad substitution

In my scenario, I wanna rename a batch of files' suffix.
e.g.: change abc.txt to abc.csv

So, what can I do as the correct syntax?

BTW, I don't know what ${i} this format is called?

  • 2
    Can you show expected input and output? – ctrl-alt-delor Jul 25 at 10:45
  • 1
    for i in ls;do echo ${i} | cut -d "." -f1;done it will work – shas Jul 25 at 11:57

You seem to want to remove everything after the first dot in the names available in the current directory.

To loop over all the names in the current directory, use

for name in *; do ...; done

Using the output of ls for anything other than for visual inspection is error prone and should be avoided. See Why *not* parse `ls` (and what do to instead)?

To remove the bit after the first dot in $name (including the dot itself), use ${name%%.*}. This is a standard parameter expansion that removes the longest suffix matching the globbing pattern .* from the value of the variable name.

To output the result of the this expansion, you may use

printf '%s\n' "${name%%.*}"

See both When is double-quoting necessary? and Why is printf better than echo?.

Your full script could be written


for name in *; do
    printf '%s\n' "${name%%.*}"

Your second question, about what ${i} is called: It's a variable expansion (sometimes the terms "parameter expansion" or "variable/parameter substitution" are used). The ${i} will be expanded to/substituted by the value of the variable i. This could also be written $i as the curly braces do not do anything special here. The only place where you may want to use ${i} instead of $i is where the expansion is part of a string and the very next character is valid in a variable's name, as in "${i}_stuff" ($i_stuff would try to expand the variable i_stuff).


You can use ${i%%.*}. It will remove everything after first occurrence of dot including dot.


echo "${i%%.*}"

will give output


In your case:

 for i in *;do echo "${i%%.*}";done

Well do not use for i in ls. See Why *not* parse `ls` (and what do to instead)?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.