41

I need to run a Bash script that can echo a 300 lines of Groovy script to a tmp file. What's the best way to do it ?

My current workaround is putting the script file online and download it.

1
  • can't you simply cat script > tmp? Commented Aug 1, 2011 at 8:47

3 Answers 3

77

Use the heredoc syntax to embed the other script within a shell script:

cat > file.tmp <<'endmsg'
script goes here...
endmsg
Sign up to request clarification or add additional context in comments.

2 Comments

Users should note the use of quotes on line one is critical if the pasted script contains shell variables -- without quotes, they will be evaluated by the current shell before the cat operation; but with quotes they will be echoed as literals exactly as pasted.
A warning should be added as well that any white-space before 'endmsg' on the final line will prevent it from working.
28

The heredoc approach is great, but you can't use it naively:

  • There are issues with not preserving spaces and tabs in the pasted content, which are hard to read on-screen, and may be triggered by the auto-cleanup functions of your text editor
  • If the end-of-heredoc marker you use occurs in the pasted content, the operation will end early; problem if the content has a nested heredoc and uses a common marker like 'EOF'.

This means a naive heredoc approach can succeed or fail depending on the content that's pasted in. That violates the principle of least amazement and is dangerous since semi-random.

I prefer wrapping the content with base64 uuencode. This eliminates the possibility of different behavior depending on the content, so you never have to think about this again.

Safer approach:

  1. Identify the content to capture, say whatever.sh
  2. uuencode -m whatever.sh whatever.sh >tmp
  3. Paste the contents of tmp into the script wrapper
  4. Use a heredoc marker that can't occur in base64

The final script looks like:

cat > file.tmp <<'_EOF'
begin-base64 644 whatever.sh
bHMgLWxSCmxzIC1sUgpscyAtbFIKbHMgLWxSCmxzIC1sUgpscyAtbFIKbHMg
LWxSCmxzIC1sUgpscyAtbFIKbHMgLWxSCmxzIC1sUgpscyAtbFIKbHMgLWxS
CmxzIC1sUgpscyAtbFIKbHMgLWxSCmxzIC1sUgpscyAtbFIKbHMgLWxSCmxz
IC1sUgpscyAtbFIK
====
_EOF
uudecode file.tmp

There is a tiny possibility any line of uuencoded data could match your heredoc marker. You probably won't use markers that are 60 characters long :) but the last line can be shorter and there is a possibility the uuencoded content could match your marker, unless the marker uses a character (like underscore) that can't occur in base64 encoding. _EOF is always safe.

It's also prudent to quote the heredoc marker like '_EOF' to prevent shell variable expansion. I don't think a base64 encoded payload can ever inadvertently reference a shell variable since $ isn't used in base64, but quoting eliminates this possibility. It also helps to establish the habit of always quoting the heredoc marker unless there's a reason you want shell expansion. This is another content-dependent behavior that's tricky since apparently random. ALWAYS quote your heredoc marker unless you know you want shell expansion within the content block!

The above is a manual procedure. It's easy to automate the same using templates.

2 Comments

The above code will write the base64 text to file.tmp, to decode it use: uudecode -o decoded_outfile < ./file.tmp This took me a minute to figure out. uudecode file.tmp by itself doesn't appear to do anything.
"..is dangerous since semi-random." ...right. This technique is also known as 'code obfuscation' and rarely appears in source. almost never really. I've never seen it, not outside working in webdev anyway. What I like to do is learn how stuff works and then just use it. It's not so crazy as it sounds
11

When you want to output to a file that requires you to use sudo, the answer is totally non-obvious!

sudo tee /etc/php/conf.d/xdebug.ini > /dev/null <<'TXT'
zend_extension=xdebug.so
xdebug.remote_enable=on
xdebug.remote_autostart=on
xdebug.remote_host=127.0.0.1
xdebug.remote_port=9000
xdebug.remote_handler=dbgp
TXT

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.