skip to Main Content

I have an HTML file that lays out images of text to create interesting typographic patterns. The images are placed in the local web page with

<img src="[path-to-project-folder]/DIR/[filename].png">.

The project folder has 15 folders with variations of all the images in them, named 001, 002 etc. I want to replace DIR with a random number from 001-015 and have tried the following in a shell script to get sed to replace the variable number in steps across my source file;

for RUN in {1..15};
do 
var1=`shuf -i 001-015 -n 1`
step=$((step + 1));
while [ ${#var1} -ne 3 ];
 do
   var1="0"$var1
 done

echo $var1
echo $step

sed  -i -e "s/DIR/$var1/"{100..1..$step} temp.htm
done

Unfortunately that results in an error of

sed: -e expression #1, char 11: unknown option to `s'

I know from attempting to debug that $var1 is replaced okay. It is $step that is not getting through. I have tried things like ${step} and combinations of backslashes but that’s just copying other scripts that work rather than truly understanding what is going on after my sed s/// argument to explain the error. The expansion section in the bash manual doesn’t seem to explain the sed error.

Can anyone help please? I’d like the output to be random like

<img src="[path-to-project-folder]/001/[filename].png"><img src="[path-to-project-folder]/014/[filename].png"><img src="[path-to-project-folder]/003/[filename].png">.

and so on. I’m using sed 4.4 on Ubuntu 18.10 with bash 4.4.20

2

Answers


  1. {100..1..$step} does not do what you think it does.

    From the bash man page:

    Expansion is performed on the command line after it has been split into words. There are seven kinds of expansion performed: brace expansion, tilde expansion, parameter and variable expansion, command substitution, arithmetic expansion, word splitting, and pathname expansion.

    The order of expansions is: brace expansion; tilde expansion, parameter and variable expansion, arithmetic expansion, and command substitution (done in a left-to-right fashion); word splitting; and pathname expansion.

    Notice that brace expansion happens before parameter expansion.
    The literal sequence of characters $step is not a valid number (increment), so the brace expansion fails.

    Consider:

    $ step=1
    $ echo "preamble"{10..1..$step}
    preamble{10..1..1}
    $
    

    A quick rewrite of your code:

    for ((step=1; step<15; step++)); do
    
        printf -v var1 '%03d' $(( (RANDOM%15)+1 ))
    
        echo $var1
        echo $step
    
        for (( n=100; n>=1; n-=step )); do
            echo "s/DIR/$var1/$n"
        done |
        sed  -i -f - temp.htm
    
    done
    
    Login or Signup to reply.
  2. There are several problems with this expression:

    sed  -i -e "s/DIR/$var1/"{100..1..$step} temp.htm
    

    If either DIR or $var contains a /, which is likely, since these are filesystem paths, you end up with an invalid s/pattern/replacement/ expression. When using sed to manipulate path values, you need to use a different delimiter.

    Given:

    dir=this/is/a/test
    newdir=that/was/a/test
    

    Compare:

    $ echo "$dir" | sed "s/$dir/$newdir/"
    sed: -e expression #1, char 11: unknown option to `s'
    

    With the following script that uses | as the s-expression delimiter:

    $ echo "$dir" | sed "s|$dir|$newdir|"
    that/was/a/test
    

    @jhnc covers the issues with the {...} expression.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search