Intro
This is the third post in a series about Emacs Org mode and the second about source code blocks.
The last post about source code blocks (blocks from now on) covered org document variables, named blocks and combining blocks.
This post will focus on how and where block result output will end up. It won't cover all of the arguments and features as I don't use all of them. If you wanna get the full picture, here is the docs.
Versions
Since last post a new Emacs version 27.1 have been released! Here are some about the release, news.
I haven't covered this type of blocks before. They are called "inline code block" and is very useful when doing one liners that returns a single value. The documentation on inline code blocks can be found here.
Here are the "inline code blocks" used to show what versions of the software I am currently using.
src_emacs-lisp{emacs-version} {{{results(=27.1=)}}}
src_emacs-lisp{org-version} {{{results(=9.4=)}}}
Default argument
Results from source block evaluation can appear in many different shapes. As list, as source block, as "raw", to file and so on.
This is how it end up if no argument if provided.
#+BEGIN_SRC shell
echo "Hello Emacs"
#+END_SRC
#+RESULTS:
: Hello Emacs
This is the same as the argument :results output
.
#+BEGIN_SRC shell :results output
echo "Hello Emacs"
#+END_SRC
#+RESULTS:
: Hello Emacs
Output code
Lets output the result into a new source code block. By default the new block gets the same language as the parent. In this case the language is shell.
#+BEGIN_SRC shell :results output code
echo "Hello Emacs"
#+END_SRC
#+RESULTS:
#+begin_src shell
Hello Emacs
#+end_src
If the output language is not the same as the parent. :wrap
can be
used to tell what language the result block will get.
#+BEGIN_SRC shell :results output code :wrap src text
echo "Hello Emacs"
#+END_SRC
#+RESULTS:
#+begin_src text
Hello Emacs
#+end_src
Append results
Results can be appended into the org document. In this case the block have been evaluated three times. I don't use this very often.
#+BEGIN_SRC shell :results output append
date +'%Y-%m-%d %H:%M:%S'
#+END_SRC
#+RESULTS:
: 2020-08-29 11:52:34
: 2020-08-29 11:52:36
: 2020-08-29 11:52:38
Table
Results can end up in nicely formatted org tables
#+BEGIN_SRC shell :results table
ps -a
#+END_SRC
#+RESULTS:
| PID | TTY | TIME | CMD |
| 5456 | tty1 | 00:00:00 | swaybg |
| 5468 | tty1 | 00:00:49 | swaybar |
| 5479 | tty1 | 00:01:12 | sh |
| 5937 | tty1 | 00:07:14 | Xwayland |
| 1279652 | pts/0 | 00:00:03 | hugo |
Or what about a nice looking NetworkManager table.
#+BEGIN_SRC shell
nmcli -g name,type,device con | awk 'BEGIN{FS=":"; OFS="\t"};{print $1, $2, $3}'
#+END_SRC
#+RESULTS:
| iPhone | 802-11-wireless | wlp0s20f3 |
| integrity_vpn | wireguard | integrity_vpn |
File
Results can be written to a file. In the results area a org link to the file containing the results is provided.
#+BEGIN_SRC shell :results file :file script.sh
echo "#!/bin/bash"
echo "echo Hey"
#+END_SRC
#+RESULTS:
[[file:script.sh]]
Here is a larger case. Write the results to a file. The filename
should be script.sh
and be written in folder /tmp
. The file
should also have execute permissions for all three user types. This
:file-mode
argument came in Org version 9.4.
#+HEADER: :results file
#+HEADER: :file script.sh
#+HEADER: :output-dir /tmp
#+HEADER: :file-mode (identity #o777)
#+BEGIN_SRC emacs-lisp
"#!/bin/bash\necho Hello World"
#+END_SRC
#+RESULTS:
[[file:/tmp/script.sh]]
Let's look on the attributes of the script.sh
file.
#+BEGIN_SRC shell :results output code :dir /tmp
ls -la | grep script.sh
#+END_SRC
#+RESULTS:
#+begin_src shell
-r-xr-xr-x 1 nils users 28 Aug 29 11:59 script.sh
#+end_src
Pass result on
Result data from one source block can be passed to another in the
same execution. You don't need to run C-c C-c
two times and have
results stored in variables. In the example on bash block generates
a string and numbers from 1 to 20. Those two lines are then passed
on to the attr_wrap
named source block. This block takes data from
the previous block and append two more lines. One with a string and
the other with numbers from 20 to 30.
#+NAME: attr_wrap
#+BEGIN_SRC shell :var data="" :results raw
echo -n "$data"
echo "... and this appends this"
echo {20..30}
#+END_SRC
Evaluate the block below, the upper block will be called
automatically.
#+HEADER: :post attr_wrap(data=*this*)
#+HEADER: :file /tmp/a.txt
#+HEADER: :results output code
#+BEGIN_SRC shell
echo "This blocks generates this data"
echo {01..10}
#+END_SRC
#+RESULTS:
#+begin_src shell
This blocks generates this data
01 02 03 04 05 06 07 08 09 10
... and this appends this
20 21 22 23 24 25 26 27 28 29 30
#+end_src
Tangle
This is a sidestep from source code block results, but it's related.
Text within a source code block can be written to a file. Using the
(org-babel-tangle)
function. (org-babel-tangle)
will look
through all of the document and find all of the source code blocks
with :tangle
arguments and write all of them to the local file
system.
This example writes some text from a source code block to a file.
#+BEGIN_SRC text :tangle /tmp/hey-from-org.txt
This is some text
#+END_SRC
#+BEGIN_SRC shell :results output code
cat /tmp/hey-from-org.txt
#+END_SRC
#+RESULTS:
#+begin_src shell
This is some text
#+end_src
Tangled file permissions
Just lite :file-mode
we have :tangle-mode
to set file
permissions when writing a file to the file system. This example is a
small bash script written to the file system and set to be executable
for all users.
#+HEADER: :tangle /tmp/hey-org-mode.sh
#+HEADER: :tangle-mode (identity #o777)
#+BEGIN_SRC shell
#!/bin/bash
echo "Hello World"
#+END_SRC
Lets check what permissions the file got after tangled.
#+BEGIN_SRC shell :results output code
ls -la /tmp | grep hey-org-mode.sh
#+END_SRC
The file got *read*, *write* and *execute* for everyone. That's what
we told in the =:tange-mode= header.
#+RESULTS:
#+begin_src shell
-rwxrwxrwx 1 john users 31 Jul 22 11:40 hey-org-mode.sh
#+end_src
Bigger example
This example combines many of the features. And in the end it generates a nicely formatted system report with a org structure.
Lets start by specifying the commands to run in the report.
#+NAME: report-commands
| Disk usage | df -h |
| Memory usage | free -h |
| Network | nmcli conn |
| System time | date |
| System uptime | uptime |
| System kernel | uname -a |
Run the table into a awk
source code block to format it into a
bash script. The result is written to a file and execute permissions
are set on the file.
#+HEADER: :stdin report-commands
#+HEADER: :results file
#+HEADER: :file /tmp/system-report.sh
#+HEADER: :file-mode (identity #o744)"
#+BEGIN_SRC awk
BEGIN {
FS="\t"
print "#!/bin/bash\n"
print "echo \"#+TITLE: $1\""
print "echo \"#+DATE: $(date +'%m-%d-%Y %H:%M:%S')\""
print "echo \"#+STARTUP: overview\""
print "echo \"\""
}
{
printf("echo \"* %s\"\n", $1)
printf("echo \"\"\n")
printf("echo \"#+BEGIN_SRC shell\"\n")
printf("echo \"%s\"\n", $2)
printf("echo \"#+END_SRC\"\n")
printf("echo \"\"\n")
printf("echo \"#+RESULTS:\"\n")
printf("echo \"#+BEGIN_SRC text\"\n")
printf("echo \"$(%s)\"\n", $2)
printf("echo \"#+END_SRC\"\n")
printf("echo \"\"\n")
}
#+END_SRC
#+RESULTS:
[[file:/tmp/system-report.sh]]
The output of the system-report.sh
will be pretty flat and will
not look nice even in org. Lets format it with some level of
indentation depending on context. This source block is only
responsible for formatting and cant do anything on it's own.
#+NAME: org_format
#+HEADER: :var data=""
#+HEADER: :results raw
#+BEGIN_SRC shell
echo -n "$data" \
| awk '$1~/BEGIN_SRC|RESULTS/,$1~/END_SRC/ { print " ", $0; next }; { print }' \
| awk '$1~/^#+/ {gsub(/^[ \t]+/, " ", $0) ; print; next}; { print }'
#+END_SRC
Let run the script and pass it though the format source code block.
#+HEADER: :dir /tmp
#+HEADER: :post org_format(data=*this*)
#+HEADER: :results output code
#+HEADER: :wrap src org
#+BEGIN_SRC shell
./system-report.sh "Daily system report"
#+END_SRC
And voila, here is the result! The report is well formatted and looks very good.
#+TITLE: Daily system report
#+DATE: 10-11-2020 21:06:41
#+STARTUP: overview
* Disk usage
#+BEGIN_SRC shell
df -h
#+END_SRC
#+RESULTS:
#+BEGIN_SRC text
Filesystem Size Used Avail Use% Mounted on
dev 16G 0 16G 0% /dev
run 16G 1.2M 16G 1% /run
/dev/mapper/cryptroot 468G 27G 418G 6% /
tmpfs 16G 187M 16G 2% /dev/shm
tmpfs 4.0M 0 4.0M 0% /sys/fs/cgroup
tmpfs 16G 2.4M 16G 1% /tmp
tmpfs 3.2G 8.7M 3.1G 1% /run/user/1000
#+END_SRC
* Memory usage
#+BEGIN_SRC shell
free -h
#+END_SRC
#+RESULTS:
#+BEGIN_SRC text
total used free shared buff/cache available
Mem: 31Gi 1.7Gi 25Gi 621Mi 3.8Gi 28Gi
Swap: 0B 0B 0B
#+END_SRC
* Network
#+BEGIN_SRC shell
nmcli conn
#+END_SRC
#+RESULTS:
#+BEGIN_SRC text
NAME UUID TYPE DEVICE
iPhone 22f467bf-5d07-41d1-a394-a7b778c4ceb2 wifi wlp0s20f3
integrity_vpn da1a14fe-ba3e-4251-bc98-03d604ec4fe0 wireguard integrity_vpn
#+END_SRC
* System time
#+BEGIN_SRC shell
date
#+END_SRC
#+RESULTS:
#+BEGIN_SRC text
Sun Oct 11 09:06:42 PM CEST 2020
#+END_SRC
* System uptime
#+BEGIN_SRC shell
uptime
#+END_SRC
#+RESULTS:
#+BEGIN_SRC text
21:06:42 up 1 day, 2:26, 1 user, load average: 0.56, 0.63, 0.58
#+END_SRC
* System kernel
#+BEGIN_SRC shell
uname -a
#+END_SRC
#+RESULTS:
#+BEGIN_SRC text
Linux arch 5.8.14-arch1-1 #1 SMP PREEMPT Wed, 07 Oct 2020 23:59:46 +0000 x86_64 GNU/Linux
#+END_SRC