2

I use sed to change text in existing files and Nano to create new files.

I change text with sed this way, for example:

sudo sed -i 's/TESTING === "1"/TESTING === "0"/g' /etc/csf/csf.conf

Is there a way to create files with it, without going inside Nano or VI and pasting text, giving permission and then execute?

Usually I do cd ~ && nano script.sh && chmod +x script.sh && ./script.sh && rm -rf script.sh and then I paste all the script content inside, then save and execute.

This time however, I want to automate even that, and just paste everything as one input and run it in place.

In other words, I look for either a way to run the script from paste, or to paste it into a temporary file and run it "in-place" the moment I close the file and by that, to run it with the least number of clicks and pastings.


Why I need this solution:

The process can be repetitive when working with several server environments and I want to save time when doing this task time and again.

The discussion about the legitimacy of such action is surly a discussion by itself...


Here is an example --- I paste the following coomand to prompt (the first one, that includes ampersands), go into Nano to create the script and right then, I paste the following script syntax, save, and it it is being executed. I wish to automate this process as to do all of this, in one pasting / one action.

cd /home/testo && sudo nano script.sh && sudo chmod +x scripts.sh && sudo ./script.sh

#!/bin/bash -x

# Basic update and upgrade:
sudo apt-get update -y
sudo apt-get upgrade -y

# Setup CSF-LFD:
sudo rm -f csf.tgz
sudo wget https://download.configserver.com/csf.tgz
sudo tar -xzf csf.tgz
sudo sh install.sh
sudo perl /etc/csf/csftest.pl
sudo sed -i 's/TESTING === "1"/TESTING === "0"/g' /etc/csf/csf.conf
sudo csf -r
  • Please don't post images of text. It makes it hard to read, we can't copy and paste it, the text isn't picked up by Google for searches, it makes the question take longer to load, etc. etc. – Zachary Brady Nov 01 '16 at 12:29
  • Okay... No problem. Thank you for noting that! –  Nov 01 '16 at 12:30
  • I deleted my answer because I misunderstood your question. – Zachary Brady Nov 01 '16 at 14:15
  • 3
    Yes, you can create files with sed but why would you want to use sed ? Have you ever heard of heredocs ? – don_crissti Nov 01 '16 at 14:24
  • Not very much more than the term itself. If this can use me for executing a copied script directly from paste then it should be useful... –  Nov 01 '16 at 15:09
  • Maybe I do not fully get you, but why is something like this not possible? sed 's/old/new/' paste_source > new_file. Apart form that: If you use sudo script.sh all the sudos in the script are negligible. – FelixJN Nov 01 '16 at 16:06
  • Because U I will then need a long line with all the commands, or I won't? –  Nov 01 '16 at 16:53
  • About sudo script.sh, you mean that the file name should be sudo SOME_PHRASE.sh ? –  Nov 01 '16 at 16:53
  • I also edited the question and tried to make it more clear. I am going to offer bounty for a solution –  Nov 01 '16 at 16:57
  • Why do you insist on doing this stuff with nano ? As I said, all you need is a heredoc. And please edit the title here, your question is not how to create files with sed. – don_crissti Nov 10 '16 at 23:36
  • I don't: Somehow I didn't read about it then and remembered now via your comment. I will now bookmark it as I'm awake for many hours now. In any case, you are invited to publish a stepped answer and I will gladly give the bounty if it worked as the shortest way of doing so... –  Nov 10 '16 at 23:45
  • Not super relevant, but you're seriously overusing sudo here. Particularly running sudo wget made me cringe a bit. Also, if you're running the script with sudo ./ses.sh, none of the sudo in the script actually do anything... – Chris Nov 15 '16 at 21:52

5 Answers5

3

In other words, I look for either a way to run the script from paste, or to paste it into a temporary file and run it "in-place" without saving any file --- To run everything is least number of clicks and pastings.

Assuming your interactive shell is a Bash or compatible shell -- you are looking for that :

bash << 'EOT'

<PASTE SCRIPT HERE>

EOT

The above code practice is called "Heredoc" (abbrivation of "Here document"), and I used it to execute all commands until EOT in a new sub-shell.

That way, you can change the working directory or alter environment. Notice EOT is not a keyword, so you can use whatever phrase you want instead of EOT (Just ensure the spelling is the same both at the start and end of the heredoc).

Single quotes are around 'EOT'are used to instruct the parent shell to not perform any substitution in the heredocument. This prevent for example variable expansion by the parent shell instead of the child shell.

As a concrete example:

sylvain@bulbizarre:~$ bash << 'EOT'
echo hello
cd /
echo We are in ${PWD}
EOT

hello
We are in /
sylvain@bulbizarre:~$   # <-- I'm still in my home directory when
                        #     back to the interactive shell

In other words, I look for either a way to run the script from paste, or to paste it into a temporary file and run it "in-place" without saving any file --- To run everything is least number of clicks and pastings.

If you want to keep a copy of the command executed, you may use that variation:

sylvain@bulbizarre:~$ tee /tmp/saved.sh << 'EOT' | bash
echo hello
cd /
echo We are in ${PWD}
EOT

hello
We are in /

sylvain@bulbizarre:~$ cat /tmp/saved.sh 
echo hello
cd /
echo We are in ${PWD}
Sylvain Leroux
  • 648
  • 4
  • 14
  • 1
    This can be useful for me; Is there a special syntax if you want to include a script that already includes several EOFs inside one big EOF? –  Nov 15 '16 at 21:51
  • 3
    @Benia EOT is not a keyword. You can use whatever you want. Some people use a single dot -- maybe in homage to the SMTP protocol ? – Sylvain Leroux Nov 15 '16 at 21:56
  • 4
    Just use different strings like EOF1 or pink_banana, as long as each nested pair is unique. – icarus Nov 15 '16 at 21:58
  • @SylvainLeroux, can you please elaborate what you mean in "I used it to execute all commands until EOT in a new sub-shell" as well as in "Single quotes are around 'EOT'are used to instruct the parent shell to not perform any substitution in the heredocument." ? I am not sure I understand, thanks for everything!!! –  Nov 16 '16 at 02:11
  • 1
    @Benia Potentially, your script could contain 'cd' or expansion ($XYZ). If you run that script directly in your interactive shell like suggested here, you will alter that environment. Running in a sub-shell seems a safer approach. As about quotes, as you type the heredoc in the parent shell but want to execute it in the child shell, there is two shells that can perform expansion, say of variables. Without the single quotes, expansion is performed in the parent shell before sending the commands to the child shell. You may want that or not... – Sylvain Leroux Nov 16 '16 at 09:48
  • Why do we need to intervene different shells here? Why not running everything in the same shell process with my current user (root or whatever); I think I miss why won't you want to run it all in the same open/existing shell. Thank you !!! –  Nov 16 '16 at 13:53
  • @Benia We don't need to create a new shell. But, usually you want that to "confine" changes in the environment to the nested shell. For example, I've noticed you prefixed every command by sudo in your example. Instead you can remove them, and run the nested shell in sudo : sudo bash << 'EOT' ... EOT. Feels much clean to me. But YMMV. – Sylvain Leroux Nov 17 '16 at 11:43
  • Oh, "nested shell" that's an interesting concept and new to me. –  Nov 17 '16 at 12:39
  • What worked for me in the end was bash /dev/fd/3 3<< 'EOT0' ... EOT0. The reason maybe is because my particular script includes some internal heredocs (and/or comments?). In any case, for more on this versia that worked for me: http://unix.stackexchange.com/questions/323797/a-script-that-is-executed-fine-from-file-breaks-when-executed-with-heredoc/323820#323820 –  Nov 17 '16 at 12:42
1

You can do this by prefixing to the script you want to paste:

echo '

and then suffixing a line thus:

'|sudo tee ses.sh >/dev/null && sudo chmod +x ses.sh && sudo ./ses.sh

and then you can copy'n'paste this whole thing in one go at the command line. For instance:

echo '#!/bin/bash
echo "Do some stuff - line 1"
echo "Do some stuff - line 2"
sudo echo -e "Do some stuff - line 3\nand line 4"
[[ 1 == 1 ]] && echo "We are all done here, bye!"
'|sudo tee ses.sh >/dev/null && sudo chmod +x ses.sh && sudo ./ses.sh

This will get thrown if the script you are pasting includes any single quotes, unfortunately.

Another way to do it that doesn't actually save a file is this:

/bin/bash -c '[script here]'

i.e. prefix /bin/bash -c ' and suffix a single '

Whether it is really advisable to be copy'n'pasting sudo scripts in this way is another question...

gogoud
  • 2,672
  • According to your answer I type in prompt: "/bin/bash -c ' " (without double quote marks) and then just copy and paste my script... I didn't add a single quote mark in the end of the script (I use only one single quote mark as in /bin/bash -c ')... Do you think it's okay? –  Nov 03 '16 at 08:53
  • @Benia you need to add the single quote at the end of the script too so that the entire text between the two single quotes is treated as an argument to the -c parameter – gogoud Nov 03 '16 at 14:52
  • It ran without it... I must note... –  Nov 03 '16 at 17:50
  • I now offer bounty. Please note that if I run echo ', and then '|sudo tee ses.sh >/dev/null && sudo chmod +x ses.sh && sudo ./ses.sh --- I don't get any text-editor like program to paste the script in run it in, and the regular bash re appears... Also note that if I just teyp echo ', then the script, and then '|sudo tee ses.sh >/dev/null && sudo chmod +x ses.sh && sudo ./ses.sh --- The script still won't run. –  Nov 10 '16 at 23:37
  • Would appreciate your take on this, gogoud. –  Nov 15 '16 at 18:45
1

In other words, I look for either a way to run the script from paste, or to paste it into a temporary file and run it "in-place" without saving any file --- To run everything is least number of clicks and pastings.

You can do exactly this using the "readline" library of your shell.

See LESS='+/^READLINE' man bash and also LESS='+/edit-and-execute-command' man bash.


For your case it is simple:

In your ~/.bashrc file, put the following line:

EDITOR=nano

Log out and log in again so the change takes effect. (Or just type . ~/.bashrc)

Then, when you want to paste in a command, type CtrlXCtrlE.

A temporary Nano buffer will be opened. Paste in (or type in) the commands you want to run.

When you save and exit, whatever you entered will be executed exactly as though you typed it in at the Bash command prompt.


If you start typing a command and then realize it is going to be long and you want the power of your editor to edit it, you can type CtrlXCtrlE at any time to edit the current command line using Nano.

Not that Nano has much power. Perhaps you should try learning Vim? :)

Again, see LESS='+/edit-and-execute-command' man bash for authoritative details.


Note that if you include an exit command, your shell will be exited. You're not running the commands as a script. You're running them in your current shell. So don't include an exit statement unless you want the same effect you would get by typing exit into your command prompt.

Wildcard
  • 36,499
0

There seem to be no need to involve sed (or any other utility) as Bash can do it by itself:

I now note that it is enough for me to do: \ and afterwards, in the "row continuation prompt", that's opened up, I could just paste my script and it would run. For example:

\

> Paste your script here (with #!/bin/bash) and it would run directly.

Note:

You could run a script without a backslash () and with just typing the script inside but in case you have a script note (#) in the start that you copy the script with --- You would want to use a backslash.

Update:

Please read the comments: This answer might not be useful in some systems if your script includes comments.

  • 1
    You don't need even the backslash - you can paste the commands in directly at the command line and they will run ok. But they are running directly in the current shell and not in a separate process, and of course you don't have a saved executable file. – gogoud Nov 04 '16 at 07:26
  • Oh, haha, I thought I will must have a double-ampersands or semicolons there, one after each command. But indeed, it runs just as you noted, without ampersands or semicolons, and without a backsalsh. As I'm new, I can't explain how this is possible without ampersands or semicolons... –  Nov 04 '16 at 15:19
  • If you run a command which attempts to read from standard in, you will likely see it "eat" the rest of the commands you typed in. Pasting multiple lines at once will work okay, it just runs each command, one by one. My answer is probably what you were looking for. – Wildcard Nov 06 '16 at 07:12
  • Right, why not simply paste the script right into the shell itself? Of course, if any errors exist in the script (such as syntax errors), you'll end up with the shell continuing on to run the subsequent commands and ignoring the error, but that would happen in a script file too without the appropriate settings (such as set -e). – ash Nov 14 '16 at 04:27
  • I now note my method here is problematic as some comments can brake execution (or thus it seemed to me last time I tried to run the script). –  Nov 15 '16 at 18:49
0

If your goal is to run scripts that do not exist on remote machines: there are better ways to achieve it without having to copy paste the entire script on to the remote machine's terminal.

For example: You can execute a local script on a remote machine through ssh:

cat script.sh | ssh me@myserver /bin/bash

Edit: Thanks for taking the time to edit in additional information to your question so that it would no longer be an xyproblem Cheers!

ktopaz
  • 21