Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Input syntax for heredoc in Bash

Tags:

bash

unix

heredoc

I'm currently learning Unix bash, through the terminal in Ubuntu 16. I was writing a simple script, so I can practice writing code for Unix. Here is a sample of the code:

report_uptime(){
cat << _EOF_
    <H2>System Uptime</H2>
    <PRE>$(uptime)</PRE>
    _EOF_
return
}

This code doesn't work and the reason is because after cat I'm supposed to use <<- instead of <<. Sometime << works. So when am I supposed to use << and when am I supposed to use<<-?

This works:

report_uptime(){
cat <<- _EOF_
    <H2>System Uptime</H2>
    <PRE>$(uptime)</PRE>
    _EOF_
return
}
like image 881
John Avatar asked Dec 18 '22 15:12

John


2 Answers

This isn't cat syntax per se; it's one of the redirection operators supported by your shell:

https://www.gnu.org/software/bash/manual/bashref.html#Here-Documents

3.6.6 Here Documents

This type of redirection instructs the shell to read input from the current source until a line containing only word (with no trailing blanks) is seen. All of the lines read up to that point are then used as the standard input for a command.

The format of here-documents is:

<<[-]word
        here-document
delimiter

No parameter and variable expansion, command substitution, arithmetic expansion, or filename expansion is performed on word. If any characters in word are quoted, the delimiter is the result of quote removal on word, and the lines in the here-document are not expanded. If word is unquoted, all lines of the here-document are subjected to parameter expansion, command substitution, and arithmetic expansion, the character sequence \newline is ignored, and ‘\’ must be used to quote the characters ‘\’, ‘$’, and ‘`’.

If the redirection operator is ‘<<-’, then all leading tab characters are stripped from input lines and the line containing delimiter. This allows here-documents within shell scripts to be indented in a natural fashion.

like image 158
melpomene Avatar answered Jan 12 '23 23:01

melpomene


This is not strictly speaking about the syntax of the cat utility, but of the syntax of the shell itself, i.e. of bash.

The construct that you're using is called a "here-document". A here-document feeds its contents into the standard input of whatever command you put before <<.

The syntax is this:

command <<word
...
contents
...
END_TAG

The word here is either exactly the same as the END_TAG, or it may be 'END_TAG', -END_TAG, or -'END_TAG'.

  • END_TAG: Without single quotes, the contents of the here-document will undergo substitution. This means that any variable, or simply put, "anything that contains a $" will be replaced with its value.

    $ tr 'a-z' 'A-Z' <<TR_END
    > This is my $HOME
    > TR_END
    THIS IS MY /USERS/KK
    

    (The >, a greater-than sign and a space, is what's called the secondary prompt. I get that because I'm typing this directly into the shell, and it needs more lines of input before it can execute the whole command. It is not typed by me.)

  • 'END_TAG': With single quotes, the contents of the here-document will not undergo substitution. This means, for example, that if you write $HOME in the here-document, it will be fed into the command just like that, not like /home/myname (or whatever your home directory may be).

    $ tr 'a-z' 'A-Z' <<'TR_END'
    > This is my $HOME
    > TR_END
    THIS IS MY $HOME
    
  • With a leading dash (-), the shell will strip off all tabs (but not spaces) at the start of each line of the here-document, including the line with the END_TAG at the end.

    $ tr 'a-z' 'A-Z' <<-TR_END
    >       This line has a tab.
    > This one does not.
    > TR_END
    THIS LINE HAS A TAB.
    THIS ONE DOES NOT.
    
  • Without a leading dash, the shell will not strip off tabs. The END_TAG needs to be the first (and only) thing on the line ending the here-document.

    $ tr 'a-z' 'A-Z' <<TR_END
    >       This line has a tab.
    > This one does not.
    > TR_END
        THIS LINE HAS A TAB.
    THIS ONE DOES NOT.
    

The bash shell also has something called "here-strings". It works in a similar fashion, but you're only feeding a single line into the command:

command <<<word

For example:

$ tr 'a-z' 'A-Z' <<<"hello world!"
HELLO WORLD!
like image 44
Kusalananda Avatar answered Jan 12 '23 22:01

Kusalananda