2

Suppose I have a simple Mathematica script file named "a.m" which contains the parameter 'a' with no assigned value:

Solve[x^2+5^a==0,x]>>a.out

What I would like to do is to create multiple script files by varying the value 'a' say from 1 to 10 and name each file by the corresponding value of 'a' such as 1.m, 2.m etc.. For this, I tried to use the 'sed' command in a for loop in the following way:

for ((i=1; i<=10; i++)); do sed 's/a/i/' <a.m >i.m;  done

so that for each fixed value of i it would replace 'a' by the numerical value and create a new file with the name 'i.m'. However above line creates a single script file named i.m with 'a' replaced by 'i'. Any suggestions ?

  • 2
    for i in {1..10}; do sed "s/a/$i/" a.m > "$i.m"; done – Costas Mar 4 '15 at 21:38
  • (@Costas, that's a completely valid answer by the way. Doesn't need to be a comment. :) – Wildcard Oct 29 '15 at 18:56
1

Shell scripts contain a lot of literal strings (command names, file names, etc.) so using the value of a variable requires a character to explicitly mark that it's a variable reference: parameter expansion consists of $ followed by the variable name (in its simplest form). In general, you need double quotes around the variable substitution. Inside single quotes, variables are not expanded at all (a $ inside '…' just stands for itself). Thus:

for ((i=1; i<=10; i++)); do
  sed "s/a/$i/" <a.m >"$i.m"
done

Inside the double parentheses, you don't need dollar signs because the double parentheses delimit arithmetic expressions, and there are no strings in arithmetic expressions so a bare word is interpreted as a variable to dereference.

Note that the sed command replaces the very first a character in the template file. You may want to choose a variable name that has less of a chance of occuring in something else like a function name. Alternatively, you could generate an assignment at the start of the script:

for ((i=1; i<=10; i++)); do
  echo "a=$i;" >"$i.m"
  cat a.m >>"$i.m"
done

The redirection operator >> appends to the existing file, in contrast with > which truncates the file if it exists.

1

I think it would be a mistake to call so many seds where only one will do. sed's claim to fame is its ability to efficiently loop over input and modify it into different output, but it can handle multiple outputs very easily as well. Here, for example, is a POSIX portable (and far more efficient) rewrite of your for loop:

echo "Solve[x^2+5^a==$((a=0)),x]>>a.out" >/tmp/i.m    ###create file + init $a
until [ "$((a+=1))" -gt 10 ]                          ###iterate + test
do    printf "h;s/a/$a/gpw /tmp/$a.m\ng;"             ###push new sed command
done| sed -nf - /tmp/i.m                              ###read + apply commands
head /tmp/[0-9].m /tmp/10.m                           ###print results

sed can read its script from stdin and apply it to a named file - which is what the sed -nf - /tmp/i.m statement above does. It can also simultaneously print its output to stdout and write its output to one or more named files. As the shell loop works it prints lines at sed which, when it is finished, amount to:

h;s/a/1/gpw /tmp/1.m
g;h;s/a/2/gpw /tmp/2.m
g;h;s/a/3/gpw /tmp/3.m
g;h;s/a/4/gpw /tmp/4.m
g;h;s/a/5/gpw /tmp/5.m
g;h;s/a/6/gpw /tmp/6.m
g;h;s/a/7/gpw /tmp/7.m
g;h;s/a/8/gpw /tmp/8.m
g;h;s/a/9/gpw /tmp/9.m
g;h;s/a/10/gpw /tmp/10.m
g

Which tells sed to...

  1. Overwrite its hold buffer with a copy of its edit buffer.
  2. globally s///ubstitute every occurrence of the letter a in its edit buffer with whatever the current value for the shell variable $a.
  3. While also both printing the results of that s///ubstitution to stdout and writing the results to the file named /tmp/$a.m where $a is an iterable.
  4. And last to get the hold buffer by overwriting the edit buffer.

sed will apply this sequence for every line in its named input file. When first called it will truncate each of its named write files, but will thereafter append each write action to each output file in sequence. Because I have only the one line in i.m, though, sed prints:

Solve[x^2+5^1==0,x]>>1.out
Solve[x^2+5^2==0,x]>>2.out
Solve[x^2+5^3==0,x]>>3.out
Solve[x^2+5^4==0,x]>>4.out
Solve[x^2+5^5==0,x]>>5.out
Solve[x^2+5^6==0,x]>>6.out
Solve[x^2+5^7==0,x]>>7.out
Solve[x^2+5^8==0,x]>>8.out
Solve[x^2+5^9==0,x]>>9.out
Solve[x^2+5^10==0,x]>>10.out

And head, reading from each of the newly created ten files in /tmp, prints:

==> /tmp/1.m <==
Solve[x^2+5^1==0,x]>>1.out

==> /tmp/2.m <==
Solve[x^2+5^2==0,x]>>2.out

==> /tmp/3.m <==
Solve[x^2+5^3==0,x]>>3.out

==> /tmp/4.m <==
Solve[x^2+5^4==0,x]>>4.out

==> /tmp/5.m <==
Solve[x^2+5^5==0,x]>>5.out

==> /tmp/6.m <==
Solve[x^2+5^6==0,x]>>6.out

==> /tmp/7.m <==
Solve[x^2+5^7==0,x]>>7.out

==> /tmp/8.m <==
Solve[x^2+5^8==0,x]>>8.out

==> /tmp/9.m <==
Solve[x^2+5^9==0,x]>>9.out

==> /tmp/10.m <==
Solve[x^2+5^10==0,x]>>10.out

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.