5

I got the following error:

./assemblyDB.116.las
test.sh: line 9: ${ls $filename | sed 's/assemblyDB.//' | sed 's/.las//'}: bad substitution

and this is the script:

for filename in $(find . -type f -name "assemblyDB.*.las"); do
   echo $filename
   no=${ls $filename | sed 's/assemblyDB.//' | sed 's/.las//'}
   echo $no
done
  • What are you trying to accomplish with the braces? Also quote your variables. – Jesse_b Feb 25 '18 at 14:04
18

${ ... } (curly braces) marks several sorts of parameter expansion, the simplest of which is just expanding the value of a variable. The stuff inside braces isn't a valid parameter name, or any other expansion, so the shell complains.

You seem to want command substitution instead, for that, the syntax is $( ... ) (regular parenthesis).

Also, the ls in ls $filename | sed... seems a bit unnecessary, the variable expands to your filename, and ls just passes it through. You could just use echo "$filename" | sed ... instead.

That said, you could do those modifications directly in the shell:

no=${filename/assemblyDB.}   # remove first match
no=${no/.las}

or, using the standard operators:

no=${filename#assemblyDB.}   # remove from start of string
no=${no%.las}                # remove from end of string

If you do run sed, you may want to note that . matches any character in regular expressions, so it would be more correct to quote it with a backslash. Also you can give one sed instance both commands: sed -e 's/assemblyDB\.//' -e 's/\.las//'.

And then for filename in $(find . -type f -name "assemblyDB.*.las"); do has the issues of parsing ls, mostly the fact that whitespace and wildcards in the file names will break it. In ksh/Bash/zsh, you could do that whole loop in the shell:

shopt -s globstar         # in Bash
for filename in **/assemblyDB.*.las; do
    ...
  • 1
    @Jesse_b, yes, but if your shell has <<<, it probably has ${var/pat/repl} too. If you do run sed, you could just give both rules to one sed instance: sed -e 's/assemblyDB\.//' -e 's/\.las//' – ilkkachu Feb 25 '18 at 14:22
  • Just wanted to point out UUOE ;) – Jesse_b Feb 25 '18 at 14:28
0

Command substitution (line 3)

for filename in $(find . -type f -name "assemblyDB.*.las"); do
   echo $filename
   no=$(ls $filename | sed 's/assemblyDB.//' | sed 's/.las//')
   echo $no
done

is equivalent, as already pointed out, to (line 3, no ls)

for filename in $(find . -type f -name "assemblyDB.*.las"); do
   echo $filename
   no=$(echo $filename | sed 's/assemblyDB.//' | sed 's/.las//')
   echo $no
done

or shorter (line 4 gone, now echo directly)

for filename in $(find . -type f -name "assemblyDB.*.las"); do
   echo $filename
   echo $filename | sed 's/assemblyDB.//' | sed 's/.las//'
done

and the sed command can be reduced to (line 3)

for filename in $(find . -type f -name "assemblyDB.*.las"); do
   echo $filename
   echo $filename | sed 's/assemblyDB.//;s/.las//'
done

or maybe extract the middle part with sed: (still line 3)

for filename in $(find . -type f -name "assemblyDB.*.las"); do
   echo $filename
   echo $filename | sed -r 's/.*assemblyDB.(.*).las/\1/'" 
done

now find-iterator instead of for-iterator: (line 1 to 3, 4 gone)

find . -type f -name "assemblyDB.*.las" -printf "%f\n" -exec sh -c "
   echo {} | sed -r 's/.*assemblyDB.(.*).las/\1/'"  ";"

assemblyDB.11.las
11
assemblyDB.9.las
9
assemblyDB.10.las
10

If your filenames are in such or a similar order, the following might work too:

for i in {8..12} ; do ls assemblyDB.$i.las && echo $i ; done 2>/dev/null

assemblyDB.9.las
9
assemblyDB.10.las
10
assemblyDB.11.las
11

(8 and 12 included, to demonstrate missing files in the sequence).

-3

Instead of ${} use backticks ` [The button below Escape on your keyboard.]

  • 2
    Please don't use backticks. Use command substitution. $( ... ) – Jesse_b Feb 25 '18 at 14:04
  • Can you explain why back ticks are bad? – Raja Nand Sharma Feb 25 '18 at 14:06
  • 3
    They are outdated, they are hard to read, they don't nest, and they can always be replaced by parenthesis command substitution. Additionally they are hard to place into inline code blocks on most markdown languages :) – Jesse_b Feb 25 '18 at 14:07
  • Yeah, that is right. But in regards to this question where did my answer go wrong?? – Raja Nand Sharma Feb 25 '18 at 14:10
  • 6
    You suggested using backticks. – Jesse_b Feb 25 '18 at 14:10

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.