bash command line - how to convert multiple line into a single line for sh -c

10,154

Solution 1

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.

Solution 2

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"}}'

Solution 3

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.

Share:
10,154

Related videos on Youtube

Weishi Z
Author by

Weishi Z

Updated on September 18, 2022

Comments

  • Weishi Z
    Weishi Z over 1 year

    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;'

    • heemayl
      heemayl over 6 years
      Why don't you put the stuffs in script and run that script with nohup (or preferably disown)?
    • kmacdonald
      kmacdonald over 6 years
      Is this about bash or sh? The question content only mentions sh, but this has been tagged bash and the title mentions bash.
  • Weishi Z
    Weishi Z over 6 years
    Thanks for pointing out There's no problem having newline characters in the argument !