2

In OSX command line, I have some logic as following.

for i in {1..10}
do
   for j in {1..10}
   do
       echo "test inner"
   done;
   echo "test outer"
done

It runs fine. But I want to run it from nohup. So I need to combine above into a single line to fit into nohup sh -c "{a single line}"

However, the following line gives error. It simply skipped all the line break from above.

sh -c 'for i in {1..10} do for j in {1..10} do echo "test inner" done; echo "test outer" done'

Error:

sh: -c: line 0: syntax error near unexpected token `echo'
sh: -c: line 0: `for i in {1..10} do for j in {1..10} do echo "test inner" done; echo "test outer" done'

Edit:

I did not want to run it as a file as the command has slightly protected credentials. The easiest way I can think of is to run it as a command so it doesn't leave a file on the shared VM. I don't know how well this protects the credentials or there is a better way. More suggestions/ideas are welcome.

Edit:

Using bash and single quote makes it work. (based on Tigger's answer)

bash -c 'for i in {1..10}; do for j in {1..10}; do echo "test inner"; done; echo "test outer"; done;'

  • Why don't you put the stuffs in script and run that script with nohup (or preferably disown)? – heemayl Aug 27 '17 at 6:46
  • Is this about bash or sh? The question content only mentions sh, but this has been tagged bash and the title mentions bash. – njsg Aug 27 '17 at 17:25
3

The way I see it is you have two options:

  1. Put that in a script-file and run THAT
  2. Replace every newline in the bigger code window above with a semicolon

I'd go with 1, personally.

3

There's no problem having newline characters in the argument to sh -c. {1..10} is zsh syntax though (now supported by a few other shells), not sh. If your sh outputs anything but {1..20} upon echo {1..20}, then it's a POSIX conformance violation and you should be ready for it to be fixed in newer versions. You can use:

zsh -c '
  for i in {1..10}
  do
     for j in {1..10}
     do
         echo "test inner"
     done
     echo "test outer"
  done'

Or

sh -c '
   i=1; while [ "$i" -le 10 ]
   do
     j=1; while [ "$j" -le 10 ]
     do
       echo "test inner"
       j=$((j + 1))
     done
     echo "test outer"
     i=$((i + 1))
  done'

But it feels silly to run 100 echo commands for that while you could do it with just one command:

awk 'BEGIN{
  for (i=1; i<=10; i++) {
    for (j=1; j<=10; j++)
      print "test inner"
    print "test outer"
  }}'

Which you can put on a single line if you want with:

awk 'BEGIN{for(i=1;i<=10;i++){for(j=1;j<=10;j++)print"test inner";print"test outer"}}'
  • Thanks for pointing out There's no problem having newline characters in the argument ! – Weishi Zeng Aug 28 '17 at 0:33
2

To convert this to a single line. I added a few ; in the correct locations:

for i in {1..10}; do for j in {1..10}; do echo "test inner ${j}"; done; echo "test outer ${i}"; done;

The above line will work with bash but to run this with sh -c you need to expand the {1..10} (as far as I know) because sh does not support that range syntax. In that case the following line works for me:

sh -c 'for i in 1 2 3 4 5 6 7 8 9 10; do for j in 1 2 3 4 5 6 7 8 9 10; do echo "test inner ${j}"; done; echo "test outer ${i}"; done;'

Note: I added ${j} and ${i} to confirm.

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.