Pass commands as input to another command (su, ssh, sh, etc)










18















I have a script where I need to start a command, then pass some additional commands as commands to that command. I tried



su
echo I should be root now:
who am I
exit
echo done.


... but it doesn't work: The su succeeds, but then the command prompt is just staring at me. If I type exit at the prompt, the echo and who am i etc start executing! And the echo done. doesn't get executed at all.



Similarly, I need for this to work over ssh:



ssh remotehost
# this should run under my account on remotehost
su
## this should run as root on remotehost
whoami
exit
## back
exit
# back


How do I solve this?




I am looking for answers which solve this in a general fashion, and which are not specific to su or ssh in particular. The intent is for this question to become a canonical for this particular pattern.











share|improve this question



















  • 2





    Related: stackoverflow.com/questions/17758235/…

    – tripleee
    Jun 2 '16 at 8:48











  • Why don't you make a shell-script with the commands you want to run as root? Then all you would have to do is run sudo sh yourshellscript.sh.

    – Jose Serodio
    Jun 11 '16 at 11:05











  • @JoseSerodio That would not work for the ssh scenario, for example (or you would have to scp the script to the remote host first), and unattractively complicates the simple case when the commands are just a few trivial ones (then you have to manage two script files, and make sure the calling script knows the path to the other one). And of course it doesn't easily extend to scenarios where some commands are dynamic (conditional on computing performed in the calling script, for example).

    – tripleee
    Jun 11 '16 at 11:43
















18















I have a script where I need to start a command, then pass some additional commands as commands to that command. I tried



su
echo I should be root now:
who am I
exit
echo done.


... but it doesn't work: The su succeeds, but then the command prompt is just staring at me. If I type exit at the prompt, the echo and who am i etc start executing! And the echo done. doesn't get executed at all.



Similarly, I need for this to work over ssh:



ssh remotehost
# this should run under my account on remotehost
su
## this should run as root on remotehost
whoami
exit
## back
exit
# back


How do I solve this?




I am looking for answers which solve this in a general fashion, and which are not specific to su or ssh in particular. The intent is for this question to become a canonical for this particular pattern.











share|improve this question



















  • 2





    Related: stackoverflow.com/questions/17758235/…

    – tripleee
    Jun 2 '16 at 8:48











  • Why don't you make a shell-script with the commands you want to run as root? Then all you would have to do is run sudo sh yourshellscript.sh.

    – Jose Serodio
    Jun 11 '16 at 11:05











  • @JoseSerodio That would not work for the ssh scenario, for example (or you would have to scp the script to the remote host first), and unattractively complicates the simple case when the commands are just a few trivial ones (then you have to manage two script files, and make sure the calling script knows the path to the other one). And of course it doesn't easily extend to scenarios where some commands are dynamic (conditional on computing performed in the calling script, for example).

    – tripleee
    Jun 11 '16 at 11:43














18












18








18


8






I have a script where I need to start a command, then pass some additional commands as commands to that command. I tried



su
echo I should be root now:
who am I
exit
echo done.


... but it doesn't work: The su succeeds, but then the command prompt is just staring at me. If I type exit at the prompt, the echo and who am i etc start executing! And the echo done. doesn't get executed at all.



Similarly, I need for this to work over ssh:



ssh remotehost
# this should run under my account on remotehost
su
## this should run as root on remotehost
whoami
exit
## back
exit
# back


How do I solve this?




I am looking for answers which solve this in a general fashion, and which are not specific to su or ssh in particular. The intent is for this question to become a canonical for this particular pattern.











share|improve this question
















I have a script where I need to start a command, then pass some additional commands as commands to that command. I tried



su
echo I should be root now:
who am I
exit
echo done.


... but it doesn't work: The su succeeds, but then the command prompt is just staring at me. If I type exit at the prompt, the echo and who am i etc start executing! And the echo done. doesn't get executed at all.



Similarly, I need for this to work over ssh:



ssh remotehost
# this should run under my account on remotehost
su
## this should run as root on remotehost
whoami
exit
## back
exit
# back


How do I solve this?




I am looking for answers which solve this in a general fashion, and which are not specific to su or ssh in particular. The intent is for this question to become a canonical for this particular pattern.








bash shell unix ssh sh






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Mar 20 '17 at 9:43









Community

11




11










asked Jun 2 '16 at 8:43









tripleeetripleee

92.1k13129184




92.1k13129184







  • 2





    Related: stackoverflow.com/questions/17758235/…

    – tripleee
    Jun 2 '16 at 8:48











  • Why don't you make a shell-script with the commands you want to run as root? Then all you would have to do is run sudo sh yourshellscript.sh.

    – Jose Serodio
    Jun 11 '16 at 11:05











  • @JoseSerodio That would not work for the ssh scenario, for example (or you would have to scp the script to the remote host first), and unattractively complicates the simple case when the commands are just a few trivial ones (then you have to manage two script files, and make sure the calling script knows the path to the other one). And of course it doesn't easily extend to scenarios where some commands are dynamic (conditional on computing performed in the calling script, for example).

    – tripleee
    Jun 11 '16 at 11:43













  • 2





    Related: stackoverflow.com/questions/17758235/…

    – tripleee
    Jun 2 '16 at 8:48











  • Why don't you make a shell-script with the commands you want to run as root? Then all you would have to do is run sudo sh yourshellscript.sh.

    – Jose Serodio
    Jun 11 '16 at 11:05











  • @JoseSerodio That would not work for the ssh scenario, for example (or you would have to scp the script to the remote host first), and unattractively complicates the simple case when the commands are just a few trivial ones (then you have to manage two script files, and make sure the calling script knows the path to the other one). And of course it doesn't easily extend to scenarios where some commands are dynamic (conditional on computing performed in the calling script, for example).

    – tripleee
    Jun 11 '16 at 11:43








2




2





Related: stackoverflow.com/questions/17758235/…

– tripleee
Jun 2 '16 at 8:48





Related: stackoverflow.com/questions/17758235/…

– tripleee
Jun 2 '16 at 8:48













Why don't you make a shell-script with the commands you want to run as root? Then all you would have to do is run sudo sh yourshellscript.sh.

– Jose Serodio
Jun 11 '16 at 11:05





Why don't you make a shell-script with the commands you want to run as root? Then all you would have to do is run sudo sh yourshellscript.sh.

– Jose Serodio
Jun 11 '16 at 11:05













@JoseSerodio That would not work for the ssh scenario, for example (or you would have to scp the script to the remote host first), and unattractively complicates the simple case when the commands are just a few trivial ones (then you have to manage two script files, and make sure the calling script knows the path to the other one). And of course it doesn't easily extend to scenarios where some commands are dynamic (conditional on computing performed in the calling script, for example).

– tripleee
Jun 11 '16 at 11:43






@JoseSerodio That would not work for the ssh scenario, for example (or you would have to scp the script to the remote host first), and unattractively complicates the simple case when the commands are just a few trivial ones (then you have to manage two script files, and make sure the calling script knows the path to the other one). And of course it doesn't easily extend to scenarios where some commands are dynamic (conditional on computing performed in the calling script, for example).

– tripleee
Jun 11 '16 at 11:43













3 Answers
3






active

oldest

votes


















17














A shell script is a sequence of commands. The shell will read the script file, and execute those commands one after the other.



In the usual case, there are no surprises here; but a frequent beginner error is assuming that some commands will take over from the shell, and start executing the following commands in the script file instead of the shell which is currently running this script. But that's not how it works.



Basically, scripts work exactly like interactive commands, but how exactly they work needs to be properly understood. Interactively, the shell reads a command (from standard input), runs that command (with input from standard input), and when it's done, it reads another command (from standard input).



Now, when executing a script, standard input is still the terminal (unless you used a redirection) but the commands are read from the script file, not from standard input. (The opposite would be very cumbersome indeed - any read would consume the next line of the script, cat would slurp all the rest of the script, and there would be no way to interact with it!) The script file only contains commands for the shell instance which executes it (though you can of course still use a here document etc to embed inputs as command arguments).



In other words, these "misunderstood" commands (su, ssh, sh, sudo, bash etc) when run alone (without arguments) will start an interactive shell, and in an interactive session, that's obviously fine; but when run from a script, that's very often not what you want.



All of these commands have ways to accept commands by ways other than in an interactive terminal session. Typically, each command supports a way to pass it commands as options or arguments:



su root -c 'who am i'
ssh user@remote uname -a
sh -c 'who am i; echo success'


Many of these commands will also accept commands on standard input:



printf 'uname -a; who am i; uptime' | su
printf 'uname -a; who am i; uptime' | ssh user@remote
printf 'uname -a; who am i; uptime' | sh


which also conveniently allows you to use here documents:



ssh user@remote <<'____HERE'
uname -a
who am i
uptime
____HERE

sh <<'____HERE'
uname -a
who am i
uptime
____HERE


For commands which accept a single command argument, that command can be sh or bash with multiple commands:



sudo sh -c 'uname -a; who am i; uptime'


As an aside, you generally don't need an explicit exit because the command will terminate anyway when it has executed the script (sequence of commands) you passed in for execution.






share|improve this answer

























  • Wouldn't a | ssh ..@... just pass stdin to a command on server side, so a | ssh ...@... 'sh' is needed.

    – andlrc
    Jun 8 '16 at 17:39






  • 2





    @andlrc No, it's not needed. In the absence of an explicit command, ssh runs a shell.

    – tripleee
    Jun 8 '16 at 19:27






  • 1





    ... Though that will be the user's login shell, which is rarely sh these days.

    – tripleee
    Jun 9 '16 at 5:02











  • @tripleee Thanks for clarifying.

    – andlrc
    Jun 9 '16 at 7:22











  • Reminder to self: add xterm examples.

    – tripleee
    Dec 19 '18 at 12:09


















14





+500









Adding to tripleee's answer:



It is important to remember that the section of the script formatted as a here-document for another shell is executed in a different shell with its own environment (and maybe even on a different machine).



If that block of your script contains parameter expansion, command substitution, and/or arithmetic expansion, then you must use the here-document facility of the shell slightly differently, depending on where you want those expansions to be performed.



1. All expansions must be performed within the scope of the parent shell.



Then the delimiter of the here document must be unquoted.



command <<DELIMITER
...
DELIMITER


Example:



#!/bin/bash

a=0
mylogin=$(whoami)
sudo sh <<END
a=1
mylogin=$(whoami)
echo a=$a
echo mylogin=$mylogin
END
echo a=$a
echo mylogin=$mylogin


Output:



a=0
mylogin=leon
a=0
mylogin=leon


2. All expansions must be performed within the scope of the child shell.



Then the delimiter of the here document must be quoted.



command <<'DELIMITER'
...
DELIMITER


Example:



#!/bin/bash

a=0
mylogin=$(whoami)
sudo sh <<'END'
a=1
mylogin=$(whoami)
echo a=$a
echo mylogin=$mylogin
END
echo a=$a
echo mylogin=$mylogin


Output:



a=1
mylogin=root
a=0
mylogin=leon


3. Some expansions must be performed in the child shell, some - in the parent.



Then the delimiter of the here document must be unquoted and you must escape those expansion expressions that must be performed in the child shell.



Example:



#!/bin/bash

a=0
mylogin=$(whoami)
sudo sh <<END
a=1
mylogin=$(whoami)
echo a=$a
echo mylogin=$mylogin
END
echo a=$a
echo mylogin=$mylogin


Output:



a=0
mylogin=root
a=0
mylogin=leon





share|improve this answer

























  • That's a good and important addition; thanks.

    – tripleee
    Jun 10 '16 at 10:49



















8














If you want a generic solution which will work for any kind of program, you can use the expect command.



Extract from the manual page:




Expect is a program that "talks" to other interactive programs according to a script. Following the script, Expect knows what can be expected from a program and what the correct response should be. An interpreted language provides branching and high-level control structures to direct the dialogue. In addition, the user can take control and interact directly when desired, afterward returning control to the script.




Here is a working example using expect:



set timeout 60

spawn sudo su -

expect "*?assword" send "*secretpassword*r"
send_user "I should be root now:"

expect "#" send "whoamir"
expect "#" send "exitr"
send_user "Done.n"
exit


The script can then be launched with a simple command:



$ expect -f custom.script


You can view a full example in the following page: http://www.journaldev.com/1405/expect-script-example-for-ssh-and-su-login-and-running-commands



Note: The answer proposed by @tripleee would only work if standard input could be read once at the start of the command, or if a tty had been allocated, and won't work for any interactive program.



Example of errors if you use a pipe



echo "su whoami" |ssh remotehost
--> su: must be run from a terminal

echo "sudo whoami" |ssh remotehost
--> sudo: no tty present and no askpass program specified


In SSH, you might force a TTY allocation with multiple -t parameters, but when sudo will ask for the password, it will fail.



Without the use of a program like expect any call to a function/program which might get information from stdin will make the next command fail:



ssh use@host <<'____HERE'
echo "Enter your name:"
read name
echo "ok."
____HERE
--> The `echo "ok."` string will be passed to the "read" command





share|improve this answer




















  • 1





    expect is a useful tool, and tangentially topical here, but as the answer to a simple shell syntax question, it's almost certainly overkill. In my 20+ years of shell programming, I have rarely needed to use it (and the availability of good general-purpose scripting languages like Perl, Python, Ruby etc makes it less necessary to ever learn).

    – tripleee
    Jun 10 '16 at 13:00






  • 2





    Your question is simple, but the solution is not as long as you want it to be generic. The solution you proposed does not take into account that you can't push everything on <stdin> at the same time. But I agree with you, using expect is something we do not expect most of the time.

    – Adam
    Jun 10 '16 at 16:43










Your Answer






StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













draft saved

draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f37586811%2fpass-commands-as-input-to-another-command-su-ssh-sh-etc%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown

























3 Answers
3






active

oldest

votes








3 Answers
3






active

oldest

votes









active

oldest

votes






active

oldest

votes









17














A shell script is a sequence of commands. The shell will read the script file, and execute those commands one after the other.



In the usual case, there are no surprises here; but a frequent beginner error is assuming that some commands will take over from the shell, and start executing the following commands in the script file instead of the shell which is currently running this script. But that's not how it works.



Basically, scripts work exactly like interactive commands, but how exactly they work needs to be properly understood. Interactively, the shell reads a command (from standard input), runs that command (with input from standard input), and when it's done, it reads another command (from standard input).



Now, when executing a script, standard input is still the terminal (unless you used a redirection) but the commands are read from the script file, not from standard input. (The opposite would be very cumbersome indeed - any read would consume the next line of the script, cat would slurp all the rest of the script, and there would be no way to interact with it!) The script file only contains commands for the shell instance which executes it (though you can of course still use a here document etc to embed inputs as command arguments).



In other words, these "misunderstood" commands (su, ssh, sh, sudo, bash etc) when run alone (without arguments) will start an interactive shell, and in an interactive session, that's obviously fine; but when run from a script, that's very often not what you want.



All of these commands have ways to accept commands by ways other than in an interactive terminal session. Typically, each command supports a way to pass it commands as options or arguments:



su root -c 'who am i'
ssh user@remote uname -a
sh -c 'who am i; echo success'


Many of these commands will also accept commands on standard input:



printf 'uname -a; who am i; uptime' | su
printf 'uname -a; who am i; uptime' | ssh user@remote
printf 'uname -a; who am i; uptime' | sh


which also conveniently allows you to use here documents:



ssh user@remote <<'____HERE'
uname -a
who am i
uptime
____HERE

sh <<'____HERE'
uname -a
who am i
uptime
____HERE


For commands which accept a single command argument, that command can be sh or bash with multiple commands:



sudo sh -c 'uname -a; who am i; uptime'


As an aside, you generally don't need an explicit exit because the command will terminate anyway when it has executed the script (sequence of commands) you passed in for execution.






share|improve this answer

























  • Wouldn't a | ssh ..@... just pass stdin to a command on server side, so a | ssh ...@... 'sh' is needed.

    – andlrc
    Jun 8 '16 at 17:39






  • 2





    @andlrc No, it's not needed. In the absence of an explicit command, ssh runs a shell.

    – tripleee
    Jun 8 '16 at 19:27






  • 1





    ... Though that will be the user's login shell, which is rarely sh these days.

    – tripleee
    Jun 9 '16 at 5:02











  • @tripleee Thanks for clarifying.

    – andlrc
    Jun 9 '16 at 7:22











  • Reminder to self: add xterm examples.

    – tripleee
    Dec 19 '18 at 12:09















17














A shell script is a sequence of commands. The shell will read the script file, and execute those commands one after the other.



In the usual case, there are no surprises here; but a frequent beginner error is assuming that some commands will take over from the shell, and start executing the following commands in the script file instead of the shell which is currently running this script. But that's not how it works.



Basically, scripts work exactly like interactive commands, but how exactly they work needs to be properly understood. Interactively, the shell reads a command (from standard input), runs that command (with input from standard input), and when it's done, it reads another command (from standard input).



Now, when executing a script, standard input is still the terminal (unless you used a redirection) but the commands are read from the script file, not from standard input. (The opposite would be very cumbersome indeed - any read would consume the next line of the script, cat would slurp all the rest of the script, and there would be no way to interact with it!) The script file only contains commands for the shell instance which executes it (though you can of course still use a here document etc to embed inputs as command arguments).



In other words, these "misunderstood" commands (su, ssh, sh, sudo, bash etc) when run alone (without arguments) will start an interactive shell, and in an interactive session, that's obviously fine; but when run from a script, that's very often not what you want.



All of these commands have ways to accept commands by ways other than in an interactive terminal session. Typically, each command supports a way to pass it commands as options or arguments:



su root -c 'who am i'
ssh user@remote uname -a
sh -c 'who am i; echo success'


Many of these commands will also accept commands on standard input:



printf 'uname -a; who am i; uptime' | su
printf 'uname -a; who am i; uptime' | ssh user@remote
printf 'uname -a; who am i; uptime' | sh


which also conveniently allows you to use here documents:



ssh user@remote <<'____HERE'
uname -a
who am i
uptime
____HERE

sh <<'____HERE'
uname -a
who am i
uptime
____HERE


For commands which accept a single command argument, that command can be sh or bash with multiple commands:



sudo sh -c 'uname -a; who am i; uptime'


As an aside, you generally don't need an explicit exit because the command will terminate anyway when it has executed the script (sequence of commands) you passed in for execution.






share|improve this answer

























  • Wouldn't a | ssh ..@... just pass stdin to a command on server side, so a | ssh ...@... 'sh' is needed.

    – andlrc
    Jun 8 '16 at 17:39






  • 2





    @andlrc No, it's not needed. In the absence of an explicit command, ssh runs a shell.

    – tripleee
    Jun 8 '16 at 19:27






  • 1





    ... Though that will be the user's login shell, which is rarely sh these days.

    – tripleee
    Jun 9 '16 at 5:02











  • @tripleee Thanks for clarifying.

    – andlrc
    Jun 9 '16 at 7:22











  • Reminder to self: add xterm examples.

    – tripleee
    Dec 19 '18 at 12:09













17












17








17







A shell script is a sequence of commands. The shell will read the script file, and execute those commands one after the other.



In the usual case, there are no surprises here; but a frequent beginner error is assuming that some commands will take over from the shell, and start executing the following commands in the script file instead of the shell which is currently running this script. But that's not how it works.



Basically, scripts work exactly like interactive commands, but how exactly they work needs to be properly understood. Interactively, the shell reads a command (from standard input), runs that command (with input from standard input), and when it's done, it reads another command (from standard input).



Now, when executing a script, standard input is still the terminal (unless you used a redirection) but the commands are read from the script file, not from standard input. (The opposite would be very cumbersome indeed - any read would consume the next line of the script, cat would slurp all the rest of the script, and there would be no way to interact with it!) The script file only contains commands for the shell instance which executes it (though you can of course still use a here document etc to embed inputs as command arguments).



In other words, these "misunderstood" commands (su, ssh, sh, sudo, bash etc) when run alone (without arguments) will start an interactive shell, and in an interactive session, that's obviously fine; but when run from a script, that's very often not what you want.



All of these commands have ways to accept commands by ways other than in an interactive terminal session. Typically, each command supports a way to pass it commands as options or arguments:



su root -c 'who am i'
ssh user@remote uname -a
sh -c 'who am i; echo success'


Many of these commands will also accept commands on standard input:



printf 'uname -a; who am i; uptime' | su
printf 'uname -a; who am i; uptime' | ssh user@remote
printf 'uname -a; who am i; uptime' | sh


which also conveniently allows you to use here documents:



ssh user@remote <<'____HERE'
uname -a
who am i
uptime
____HERE

sh <<'____HERE'
uname -a
who am i
uptime
____HERE


For commands which accept a single command argument, that command can be sh or bash with multiple commands:



sudo sh -c 'uname -a; who am i; uptime'


As an aside, you generally don't need an explicit exit because the command will terminate anyway when it has executed the script (sequence of commands) you passed in for execution.






share|improve this answer















A shell script is a sequence of commands. The shell will read the script file, and execute those commands one after the other.



In the usual case, there are no surprises here; but a frequent beginner error is assuming that some commands will take over from the shell, and start executing the following commands in the script file instead of the shell which is currently running this script. But that's not how it works.



Basically, scripts work exactly like interactive commands, but how exactly they work needs to be properly understood. Interactively, the shell reads a command (from standard input), runs that command (with input from standard input), and when it's done, it reads another command (from standard input).



Now, when executing a script, standard input is still the terminal (unless you used a redirection) but the commands are read from the script file, not from standard input. (The opposite would be very cumbersome indeed - any read would consume the next line of the script, cat would slurp all the rest of the script, and there would be no way to interact with it!) The script file only contains commands for the shell instance which executes it (though you can of course still use a here document etc to embed inputs as command arguments).



In other words, these "misunderstood" commands (su, ssh, sh, sudo, bash etc) when run alone (without arguments) will start an interactive shell, and in an interactive session, that's obviously fine; but when run from a script, that's very often not what you want.



All of these commands have ways to accept commands by ways other than in an interactive terminal session. Typically, each command supports a way to pass it commands as options or arguments:



su root -c 'who am i'
ssh user@remote uname -a
sh -c 'who am i; echo success'


Many of these commands will also accept commands on standard input:



printf 'uname -a; who am i; uptime' | su
printf 'uname -a; who am i; uptime' | ssh user@remote
printf 'uname -a; who am i; uptime' | sh


which also conveniently allows you to use here documents:



ssh user@remote <<'____HERE'
uname -a
who am i
uptime
____HERE

sh <<'____HERE'
uname -a
who am i
uptime
____HERE


For commands which accept a single command argument, that command can be sh or bash with multiple commands:



sudo sh -c 'uname -a; who am i; uptime'


As an aside, you generally don't need an explicit exit because the command will terminate anyway when it has executed the script (sequence of commands) you passed in for execution.







share|improve this answer














share|improve this answer



share|improve this answer








edited Jan 29 at 9:48

























answered Jun 2 '16 at 8:43









tripleeetripleee

92.1k13129184




92.1k13129184












  • Wouldn't a | ssh ..@... just pass stdin to a command on server side, so a | ssh ...@... 'sh' is needed.

    – andlrc
    Jun 8 '16 at 17:39






  • 2





    @andlrc No, it's not needed. In the absence of an explicit command, ssh runs a shell.

    – tripleee
    Jun 8 '16 at 19:27






  • 1





    ... Though that will be the user's login shell, which is rarely sh these days.

    – tripleee
    Jun 9 '16 at 5:02











  • @tripleee Thanks for clarifying.

    – andlrc
    Jun 9 '16 at 7:22











  • Reminder to self: add xterm examples.

    – tripleee
    Dec 19 '18 at 12:09

















  • Wouldn't a | ssh ..@... just pass stdin to a command on server side, so a | ssh ...@... 'sh' is needed.

    – andlrc
    Jun 8 '16 at 17:39






  • 2





    @andlrc No, it's not needed. In the absence of an explicit command, ssh runs a shell.

    – tripleee
    Jun 8 '16 at 19:27






  • 1





    ... Though that will be the user's login shell, which is rarely sh these days.

    – tripleee
    Jun 9 '16 at 5:02











  • @tripleee Thanks for clarifying.

    – andlrc
    Jun 9 '16 at 7:22











  • Reminder to self: add xterm examples.

    – tripleee
    Dec 19 '18 at 12:09
















Wouldn't a | ssh ..@... just pass stdin to a command on server side, so a | ssh ...@... 'sh' is needed.

– andlrc
Jun 8 '16 at 17:39





Wouldn't a | ssh ..@... just pass stdin to a command on server side, so a | ssh ...@... 'sh' is needed.

– andlrc
Jun 8 '16 at 17:39




2




2





@andlrc No, it's not needed. In the absence of an explicit command, ssh runs a shell.

– tripleee
Jun 8 '16 at 19:27





@andlrc No, it's not needed. In the absence of an explicit command, ssh runs a shell.

– tripleee
Jun 8 '16 at 19:27




1




1





... Though that will be the user's login shell, which is rarely sh these days.

– tripleee
Jun 9 '16 at 5:02





... Though that will be the user's login shell, which is rarely sh these days.

– tripleee
Jun 9 '16 at 5:02













@tripleee Thanks for clarifying.

– andlrc
Jun 9 '16 at 7:22





@tripleee Thanks for clarifying.

– andlrc
Jun 9 '16 at 7:22













Reminder to self: add xterm examples.

– tripleee
Dec 19 '18 at 12:09





Reminder to self: add xterm examples.

– tripleee
Dec 19 '18 at 12:09













14





+500









Adding to tripleee's answer:



It is important to remember that the section of the script formatted as a here-document for another shell is executed in a different shell with its own environment (and maybe even on a different machine).



If that block of your script contains parameter expansion, command substitution, and/or arithmetic expansion, then you must use the here-document facility of the shell slightly differently, depending on where you want those expansions to be performed.



1. All expansions must be performed within the scope of the parent shell.



Then the delimiter of the here document must be unquoted.



command <<DELIMITER
...
DELIMITER


Example:



#!/bin/bash

a=0
mylogin=$(whoami)
sudo sh <<END
a=1
mylogin=$(whoami)
echo a=$a
echo mylogin=$mylogin
END
echo a=$a
echo mylogin=$mylogin


Output:



a=0
mylogin=leon
a=0
mylogin=leon


2. All expansions must be performed within the scope of the child shell.



Then the delimiter of the here document must be quoted.



command <<'DELIMITER'
...
DELIMITER


Example:



#!/bin/bash

a=0
mylogin=$(whoami)
sudo sh <<'END'
a=1
mylogin=$(whoami)
echo a=$a
echo mylogin=$mylogin
END
echo a=$a
echo mylogin=$mylogin


Output:



a=1
mylogin=root
a=0
mylogin=leon


3. Some expansions must be performed in the child shell, some - in the parent.



Then the delimiter of the here document must be unquoted and you must escape those expansion expressions that must be performed in the child shell.



Example:



#!/bin/bash

a=0
mylogin=$(whoami)
sudo sh <<END
a=1
mylogin=$(whoami)
echo a=$a
echo mylogin=$mylogin
END
echo a=$a
echo mylogin=$mylogin


Output:



a=0
mylogin=root
a=0
mylogin=leon





share|improve this answer

























  • That's a good and important addition; thanks.

    – tripleee
    Jun 10 '16 at 10:49
















14





+500









Adding to tripleee's answer:



It is important to remember that the section of the script formatted as a here-document for another shell is executed in a different shell with its own environment (and maybe even on a different machine).



If that block of your script contains parameter expansion, command substitution, and/or arithmetic expansion, then you must use the here-document facility of the shell slightly differently, depending on where you want those expansions to be performed.



1. All expansions must be performed within the scope of the parent shell.



Then the delimiter of the here document must be unquoted.



command <<DELIMITER
...
DELIMITER


Example:



#!/bin/bash

a=0
mylogin=$(whoami)
sudo sh <<END
a=1
mylogin=$(whoami)
echo a=$a
echo mylogin=$mylogin
END
echo a=$a
echo mylogin=$mylogin


Output:



a=0
mylogin=leon
a=0
mylogin=leon


2. All expansions must be performed within the scope of the child shell.



Then the delimiter of the here document must be quoted.



command <<'DELIMITER'
...
DELIMITER


Example:



#!/bin/bash

a=0
mylogin=$(whoami)
sudo sh <<'END'
a=1
mylogin=$(whoami)
echo a=$a
echo mylogin=$mylogin
END
echo a=$a
echo mylogin=$mylogin


Output:



a=1
mylogin=root
a=0
mylogin=leon


3. Some expansions must be performed in the child shell, some - in the parent.



Then the delimiter of the here document must be unquoted and you must escape those expansion expressions that must be performed in the child shell.



Example:



#!/bin/bash

a=0
mylogin=$(whoami)
sudo sh <<END
a=1
mylogin=$(whoami)
echo a=$a
echo mylogin=$mylogin
END
echo a=$a
echo mylogin=$mylogin


Output:



a=0
mylogin=root
a=0
mylogin=leon





share|improve this answer

























  • That's a good and important addition; thanks.

    – tripleee
    Jun 10 '16 at 10:49














14





+500







14





+500



14




+500





Adding to tripleee's answer:



It is important to remember that the section of the script formatted as a here-document for another shell is executed in a different shell with its own environment (and maybe even on a different machine).



If that block of your script contains parameter expansion, command substitution, and/or arithmetic expansion, then you must use the here-document facility of the shell slightly differently, depending on where you want those expansions to be performed.



1. All expansions must be performed within the scope of the parent shell.



Then the delimiter of the here document must be unquoted.



command <<DELIMITER
...
DELIMITER


Example:



#!/bin/bash

a=0
mylogin=$(whoami)
sudo sh <<END
a=1
mylogin=$(whoami)
echo a=$a
echo mylogin=$mylogin
END
echo a=$a
echo mylogin=$mylogin


Output:



a=0
mylogin=leon
a=0
mylogin=leon


2. All expansions must be performed within the scope of the child shell.



Then the delimiter of the here document must be quoted.



command <<'DELIMITER'
...
DELIMITER


Example:



#!/bin/bash

a=0
mylogin=$(whoami)
sudo sh <<'END'
a=1
mylogin=$(whoami)
echo a=$a
echo mylogin=$mylogin
END
echo a=$a
echo mylogin=$mylogin


Output:



a=1
mylogin=root
a=0
mylogin=leon


3. Some expansions must be performed in the child shell, some - in the parent.



Then the delimiter of the here document must be unquoted and you must escape those expansion expressions that must be performed in the child shell.



Example:



#!/bin/bash

a=0
mylogin=$(whoami)
sudo sh <<END
a=1
mylogin=$(whoami)
echo a=$a
echo mylogin=$mylogin
END
echo a=$a
echo mylogin=$mylogin


Output:



a=0
mylogin=root
a=0
mylogin=leon





share|improve this answer















Adding to tripleee's answer:



It is important to remember that the section of the script formatted as a here-document for another shell is executed in a different shell with its own environment (and maybe even on a different machine).



If that block of your script contains parameter expansion, command substitution, and/or arithmetic expansion, then you must use the here-document facility of the shell slightly differently, depending on where you want those expansions to be performed.



1. All expansions must be performed within the scope of the parent shell.



Then the delimiter of the here document must be unquoted.



command <<DELIMITER
...
DELIMITER


Example:



#!/bin/bash

a=0
mylogin=$(whoami)
sudo sh <<END
a=1
mylogin=$(whoami)
echo a=$a
echo mylogin=$mylogin
END
echo a=$a
echo mylogin=$mylogin


Output:



a=0
mylogin=leon
a=0
mylogin=leon


2. All expansions must be performed within the scope of the child shell.



Then the delimiter of the here document must be quoted.



command <<'DELIMITER'
...
DELIMITER


Example:



#!/bin/bash

a=0
mylogin=$(whoami)
sudo sh <<'END'
a=1
mylogin=$(whoami)
echo a=$a
echo mylogin=$mylogin
END
echo a=$a
echo mylogin=$mylogin


Output:



a=1
mylogin=root
a=0
mylogin=leon


3. Some expansions must be performed in the child shell, some - in the parent.



Then the delimiter of the here document must be unquoted and you must escape those expansion expressions that must be performed in the child shell.



Example:



#!/bin/bash

a=0
mylogin=$(whoami)
sudo sh <<END
a=1
mylogin=$(whoami)
echo a=$a
echo mylogin=$mylogin
END
echo a=$a
echo mylogin=$mylogin


Output:



a=0
mylogin=root
a=0
mylogin=leon






share|improve this answer














share|improve this answer



share|improve this answer








edited May 23 '17 at 11:47









Community

11




11










answered Jun 10 '16 at 10:41









LeonLeon

21.1k23270




21.1k23270












  • That's a good and important addition; thanks.

    – tripleee
    Jun 10 '16 at 10:49


















  • That's a good and important addition; thanks.

    – tripleee
    Jun 10 '16 at 10:49

















That's a good and important addition; thanks.

– tripleee
Jun 10 '16 at 10:49






That's a good and important addition; thanks.

– tripleee
Jun 10 '16 at 10:49












8














If you want a generic solution which will work for any kind of program, you can use the expect command.



Extract from the manual page:




Expect is a program that "talks" to other interactive programs according to a script. Following the script, Expect knows what can be expected from a program and what the correct response should be. An interpreted language provides branching and high-level control structures to direct the dialogue. In addition, the user can take control and interact directly when desired, afterward returning control to the script.




Here is a working example using expect:



set timeout 60

spawn sudo su -

expect "*?assword" send "*secretpassword*r"
send_user "I should be root now:"

expect "#" send "whoamir"
expect "#" send "exitr"
send_user "Done.n"
exit


The script can then be launched with a simple command:



$ expect -f custom.script


You can view a full example in the following page: http://www.journaldev.com/1405/expect-script-example-for-ssh-and-su-login-and-running-commands



Note: The answer proposed by @tripleee would only work if standard input could be read once at the start of the command, or if a tty had been allocated, and won't work for any interactive program.



Example of errors if you use a pipe



echo "su whoami" |ssh remotehost
--> su: must be run from a terminal

echo "sudo whoami" |ssh remotehost
--> sudo: no tty present and no askpass program specified


In SSH, you might force a TTY allocation with multiple -t parameters, but when sudo will ask for the password, it will fail.



Without the use of a program like expect any call to a function/program which might get information from stdin will make the next command fail:



ssh use@host <<'____HERE'
echo "Enter your name:"
read name
echo "ok."
____HERE
--> The `echo "ok."` string will be passed to the "read" command





share|improve this answer




















  • 1





    expect is a useful tool, and tangentially topical here, but as the answer to a simple shell syntax question, it's almost certainly overkill. In my 20+ years of shell programming, I have rarely needed to use it (and the availability of good general-purpose scripting languages like Perl, Python, Ruby etc makes it less necessary to ever learn).

    – tripleee
    Jun 10 '16 at 13:00






  • 2





    Your question is simple, but the solution is not as long as you want it to be generic. The solution you proposed does not take into account that you can't push everything on <stdin> at the same time. But I agree with you, using expect is something we do not expect most of the time.

    – Adam
    Jun 10 '16 at 16:43















8














If you want a generic solution which will work for any kind of program, you can use the expect command.



Extract from the manual page:




Expect is a program that "talks" to other interactive programs according to a script. Following the script, Expect knows what can be expected from a program and what the correct response should be. An interpreted language provides branching and high-level control structures to direct the dialogue. In addition, the user can take control and interact directly when desired, afterward returning control to the script.




Here is a working example using expect:



set timeout 60

spawn sudo su -

expect "*?assword" send "*secretpassword*r"
send_user "I should be root now:"

expect "#" send "whoamir"
expect "#" send "exitr"
send_user "Done.n"
exit


The script can then be launched with a simple command:



$ expect -f custom.script


You can view a full example in the following page: http://www.journaldev.com/1405/expect-script-example-for-ssh-and-su-login-and-running-commands



Note: The answer proposed by @tripleee would only work if standard input could be read once at the start of the command, or if a tty had been allocated, and won't work for any interactive program.



Example of errors if you use a pipe



echo "su whoami" |ssh remotehost
--> su: must be run from a terminal

echo "sudo whoami" |ssh remotehost
--> sudo: no tty present and no askpass program specified


In SSH, you might force a TTY allocation with multiple -t parameters, but when sudo will ask for the password, it will fail.



Without the use of a program like expect any call to a function/program which might get information from stdin will make the next command fail:



ssh use@host <<'____HERE'
echo "Enter your name:"
read name
echo "ok."
____HERE
--> The `echo "ok."` string will be passed to the "read" command





share|improve this answer




















  • 1





    expect is a useful tool, and tangentially topical here, but as the answer to a simple shell syntax question, it's almost certainly overkill. In my 20+ years of shell programming, I have rarely needed to use it (and the availability of good general-purpose scripting languages like Perl, Python, Ruby etc makes it less necessary to ever learn).

    – tripleee
    Jun 10 '16 at 13:00






  • 2





    Your question is simple, but the solution is not as long as you want it to be generic. The solution you proposed does not take into account that you can't push everything on <stdin> at the same time. But I agree with you, using expect is something we do not expect most of the time.

    – Adam
    Jun 10 '16 at 16:43













8












8








8







If you want a generic solution which will work for any kind of program, you can use the expect command.



Extract from the manual page:




Expect is a program that "talks" to other interactive programs according to a script. Following the script, Expect knows what can be expected from a program and what the correct response should be. An interpreted language provides branching and high-level control structures to direct the dialogue. In addition, the user can take control and interact directly when desired, afterward returning control to the script.




Here is a working example using expect:



set timeout 60

spawn sudo su -

expect "*?assword" send "*secretpassword*r"
send_user "I should be root now:"

expect "#" send "whoamir"
expect "#" send "exitr"
send_user "Done.n"
exit


The script can then be launched with a simple command:



$ expect -f custom.script


You can view a full example in the following page: http://www.journaldev.com/1405/expect-script-example-for-ssh-and-su-login-and-running-commands



Note: The answer proposed by @tripleee would only work if standard input could be read once at the start of the command, or if a tty had been allocated, and won't work for any interactive program.



Example of errors if you use a pipe



echo "su whoami" |ssh remotehost
--> su: must be run from a terminal

echo "sudo whoami" |ssh remotehost
--> sudo: no tty present and no askpass program specified


In SSH, you might force a TTY allocation with multiple -t parameters, but when sudo will ask for the password, it will fail.



Without the use of a program like expect any call to a function/program which might get information from stdin will make the next command fail:



ssh use@host <<'____HERE'
echo "Enter your name:"
read name
echo "ok."
____HERE
--> The `echo "ok."` string will be passed to the "read" command





share|improve this answer















If you want a generic solution which will work for any kind of program, you can use the expect command.



Extract from the manual page:




Expect is a program that "talks" to other interactive programs according to a script. Following the script, Expect knows what can be expected from a program and what the correct response should be. An interpreted language provides branching and high-level control structures to direct the dialogue. In addition, the user can take control and interact directly when desired, afterward returning control to the script.




Here is a working example using expect:



set timeout 60

spawn sudo su -

expect "*?assword" send "*secretpassword*r"
send_user "I should be root now:"

expect "#" send "whoamir"
expect "#" send "exitr"
send_user "Done.n"
exit


The script can then be launched with a simple command:



$ expect -f custom.script


You can view a full example in the following page: http://www.journaldev.com/1405/expect-script-example-for-ssh-and-su-login-and-running-commands



Note: The answer proposed by @tripleee would only work if standard input could be read once at the start of the command, or if a tty had been allocated, and won't work for any interactive program.



Example of errors if you use a pipe



echo "su whoami" |ssh remotehost
--> su: must be run from a terminal

echo "sudo whoami" |ssh remotehost
--> sudo: no tty present and no askpass program specified


In SSH, you might force a TTY allocation with multiple -t parameters, but when sudo will ask for the password, it will fail.



Without the use of a program like expect any call to a function/program which might get information from stdin will make the next command fail:



ssh use@host <<'____HERE'
echo "Enter your name:"
read name
echo "ok."
____HERE
--> The `echo "ok."` string will be passed to the "read" command






share|improve this answer














share|improve this answer



share|improve this answer








edited Jun 13 '16 at 8:13

























answered Jun 10 '16 at 12:18









AdamAdam

12.1k1735




12.1k1735







  • 1





    expect is a useful tool, and tangentially topical here, but as the answer to a simple shell syntax question, it's almost certainly overkill. In my 20+ years of shell programming, I have rarely needed to use it (and the availability of good general-purpose scripting languages like Perl, Python, Ruby etc makes it less necessary to ever learn).

    – tripleee
    Jun 10 '16 at 13:00






  • 2





    Your question is simple, but the solution is not as long as you want it to be generic. The solution you proposed does not take into account that you can't push everything on <stdin> at the same time. But I agree with you, using expect is something we do not expect most of the time.

    – Adam
    Jun 10 '16 at 16:43












  • 1





    expect is a useful tool, and tangentially topical here, but as the answer to a simple shell syntax question, it's almost certainly overkill. In my 20+ years of shell programming, I have rarely needed to use it (and the availability of good general-purpose scripting languages like Perl, Python, Ruby etc makes it less necessary to ever learn).

    – tripleee
    Jun 10 '16 at 13:00






  • 2





    Your question is simple, but the solution is not as long as you want it to be generic. The solution you proposed does not take into account that you can't push everything on <stdin> at the same time. But I agree with you, using expect is something we do not expect most of the time.

    – Adam
    Jun 10 '16 at 16:43







1




1





expect is a useful tool, and tangentially topical here, but as the answer to a simple shell syntax question, it's almost certainly overkill. In my 20+ years of shell programming, I have rarely needed to use it (and the availability of good general-purpose scripting languages like Perl, Python, Ruby etc makes it less necessary to ever learn).

– tripleee
Jun 10 '16 at 13:00





expect is a useful tool, and tangentially topical here, but as the answer to a simple shell syntax question, it's almost certainly overkill. In my 20+ years of shell programming, I have rarely needed to use it (and the availability of good general-purpose scripting languages like Perl, Python, Ruby etc makes it less necessary to ever learn).

– tripleee
Jun 10 '16 at 13:00




2




2





Your question is simple, but the solution is not as long as you want it to be generic. The solution you proposed does not take into account that you can't push everything on <stdin> at the same time. But I agree with you, using expect is something we do not expect most of the time.

– Adam
Jun 10 '16 at 16:43





Your question is simple, but the solution is not as long as you want it to be generic. The solution you proposed does not take into account that you can't push everything on <stdin> at the same time. But I agree with you, using expect is something we do not expect most of the time.

– Adam
Jun 10 '16 at 16:43

















draft saved

draft discarded
















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid


  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f37586811%2fpass-commands-as-input-to-another-command-su-ssh-sh-etc%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Top Tejano songwriter Luis Silva dead of heart attack at 64

政党

天津地下鉄3号線