Pass commands as input to another command (su, ssh, sh, etc)
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
orssh
in particular. The intent is for this question to become a canonical for this particular pattern.
bash shell unix ssh sh
add a comment |
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
orssh
in particular. The intent is for this question to become a canonical for this particular pattern.
bash shell unix ssh sh
2
Related: stackoverflow.com/questions/17758235/…
– tripleee
Jun 2 '16 at 8:48
Why don't you make ashell-script
with the commands you want to run as root? Then all you would have to do is runsudo sh yourshellscript.sh
.
– Jose Serodio
Jun 11 '16 at 11:05
@JoseSerodio That would not work for thessh
scenario, for example (or you would have toscp
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
add a comment |
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
orssh
in particular. The intent is for this question to become a canonical for this particular pattern.
bash shell unix ssh sh
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
orssh
in particular. The intent is for this question to become a canonical for this particular pattern.
bash shell unix ssh sh
bash shell unix ssh sh
edited Mar 20 '17 at 9:43
Community♦
11
11
asked Jun 2 '16 at 8:43
tripleeetripleee
93.1k13130184
93.1k13130184
2
Related: stackoverflow.com/questions/17758235/…
– tripleee
Jun 2 '16 at 8:48
Why don't you make ashell-script
with the commands you want to run as root? Then all you would have to do is runsudo sh yourshellscript.sh
.
– Jose Serodio
Jun 11 '16 at 11:05
@JoseSerodio That would not work for thessh
scenario, for example (or you would have toscp
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
add a comment |
2
Related: stackoverflow.com/questions/17758235/…
– tripleee
Jun 2 '16 at 8:48
Why don't you make ashell-script
with the commands you want to run as root? Then all you would have to do is runsudo sh yourshellscript.sh
.
– Jose Serodio
Jun 11 '16 at 11:05
@JoseSerodio That would not work for thessh
scenario, for example (or you would have toscp
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
add a comment |
3 Answers
3
active
oldest
votes
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.
Wouldn'ta | ssh ..@...
just pass stdin to a command on server side, soa | 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 rarelysh
these days.
– tripleee
Jun 9 '16 at 5:02
@tripleee Thanks for clarifying.
– andlrc
Jun 9 '16 at 7:22
Reminder to self: addxterm
examples.
– tripleee
Dec 19 '18 at 12:09
add a comment |
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
That's a good and important addition; thanks.
– tripleee
Jun 10 '16 at 10:49
add a comment |
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
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, usingexpect
is something we do not expect most of the time.
– Adam
Jun 10 '16 at 16:43
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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.
Wouldn'ta | ssh ..@...
just pass stdin to a command on server side, soa | 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 rarelysh
these days.
– tripleee
Jun 9 '16 at 5:02
@tripleee Thanks for clarifying.
– andlrc
Jun 9 '16 at 7:22
Reminder to self: addxterm
examples.
– tripleee
Dec 19 '18 at 12:09
add a comment |
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.
Wouldn'ta | ssh ..@...
just pass stdin to a command on server side, soa | 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 rarelysh
these days.
– tripleee
Jun 9 '16 at 5:02
@tripleee Thanks for clarifying.
– andlrc
Jun 9 '16 at 7:22
Reminder to self: addxterm
examples.
– tripleee
Dec 19 '18 at 12:09
add a comment |
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.
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.
edited Jan 29 at 9:48
answered Jun 2 '16 at 8:43
tripleeetripleee
93.1k13130184
93.1k13130184
Wouldn'ta | ssh ..@...
just pass stdin to a command on server side, soa | 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 rarelysh
these days.
– tripleee
Jun 9 '16 at 5:02
@tripleee Thanks for clarifying.
– andlrc
Jun 9 '16 at 7:22
Reminder to self: addxterm
examples.
– tripleee
Dec 19 '18 at 12:09
add a comment |
Wouldn'ta | ssh ..@...
just pass stdin to a command on server side, soa | 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 rarelysh
these days.
– tripleee
Jun 9 '16 at 5:02
@tripleee Thanks for clarifying.
– andlrc
Jun 9 '16 at 7:22
Reminder to self: addxterm
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
add a comment |
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
That's a good and important addition; thanks.
– tripleee
Jun 10 '16 at 10:49
add a comment |
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
That's a good and important addition; thanks.
– tripleee
Jun 10 '16 at 10:49
add a comment |
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
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
edited May 23 '17 at 11:47
Community♦
11
11
answered Jun 10 '16 at 10:41
LeonLeon
21.3k23270
21.3k23270
That's a good and important addition; thanks.
– tripleee
Jun 10 '16 at 10:49
add a comment |
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
add a comment |
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
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, usingexpect
is something we do not expect most of the time.
– Adam
Jun 10 '16 at 16:43
add a comment |
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
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, usingexpect
is something we do not expect most of the time.
– Adam
Jun 10 '16 at 16:43
add a comment |
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
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
edited Jun 13 '16 at 8:13
answered Jun 10 '16 at 12:18
AdamAdam
12.2k1735
12.2k1735
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, usingexpect
is something we do not expect most of the time.
– Adam
Jun 10 '16 at 16:43
add a comment |
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, usingexpect
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
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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 runsudo 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 toscp
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