1

I define a global remote session for all my sh block code with properties

:PROPERTIES
:HEADER-ARGS:bash: :dir /ssh:xxx@myvm:/home/xxx/
:END:

In my other bash blocks, I inherit this property, but after working folder was created, my code are executed in sub folder of /home/xxx

Here an example with creation of two folders in /home/xxx : todolist1 and todolist2

I finally found that noweb is a good path to follow :

* Example
:PROPERTIES:
:HEADER-ARGS:bash: :dir /ssh:xxx@myvm:/home/xxx/
:END:

#+NAME: createdir
#+BEGIN_SRC bash :var folder="" :exports none
if [ -n "${folder}" ] ; then
    if [ -d "${folder}" ]; then
        rm -Rf "${folder}"
    fi
    mkdir "${folder}"
fi
#+END_SRC

#+NAME: gotodir
#+BEGIN_SRC bash :var folder="" :exports none
if [ -n "${folder}" ] ; then
    cd "${folder}"
fi
#+END_SRC

#+BEGIN_SRC bash :var folder="todolist1" :noweb yes :exports both
<<createdir>>
#+END_SRC

#+BEGIN_SRC bash :var folder="todolist2" :noweb yes :exports both
<<createdir>>
#+END_SRC

// First action on todolist 1
#+NAME: addmytodolist1
#+BEGIN_SRC bash :var folder="todolist1" :noweb yes :exports both :results verbatim
<<gotodir>>
cat > todolist1.org <<EOF 
#mytodolist
- [ ] item 1
- [X] item 2
EOF
#+END_SRC

// Second action on todolist 1
#+NAME: addmytodolist12
#+BEGIN_SRC bash :var folder="todolist1" :noweb yes :exports both :results verbatim
<<gotodir>>
cat >> todolist1.org <<EOF 
- [ ] item 3
EOF
#+END_SRC

// First action on todolist 2
#+NAME: addmytodolist2
#+BEGIN_SRC bash :var folder="todolist2" :noweb yes :exports both :results verbatim
<<gotodir>>
cat > todolist2.org <<EOF 
- [X] item 1
- [X] item 2
- [ ] item 3
- [X] item 4
EOF
#+END_SRC

To write less verbose and better maintainable code, i try without success :

  • to hide the <<gotodir>> instruction from export using :prologue <<gotodir>> => failed

  • I also try to directly expand dir: into header args, but that doesn't take in account the remote TRAMP ssh connexion : #BEGIN_SRC sh :var folder="todolist1" :dir (expand-file-name (org-sbe "gotodir"))

  • I suppose it exist some elisp code to get TRAMP ssh folder, and rewrite it/overwrite it by using new url {trampfolder}/todolist1 or {trampfolder}/todolist2 ?

There are probably better and more robust way to do that, I'm interested to know what org-mode/org-babel guru :) !

0

Use elisp in the :dir header to fetch the value the :HEADER-ARGS:bash from the PROPERTIES drawer, remove original :dir string and return new value with a subdirectory appended.

  • For example, to append the todolist1, subdirectory, set the header below on the bash code block.

    :dir (format "%s/todolist1" (replace-regexp-in-string ":dir +" "" (org-entry-get nil "HEADER-ARGS:bash" t)))
    

Below is an full example, which executes 3 bash code blocks via tramp in the default, todolist1, and todolist2 directories.

* Example
:PROPERTIES:
:HEADER-ARGS:bash: :dir /ssh:xxx@myvm:/home/xxx
:END:

- The block below will execute in =/ssh:xxx@myvm:/home/xxx=, i.e. the default =:dir=

  #+BEGIN_SRC bash 
  echo "$USER@$HOSTNAME executed this block in the $PWD directory"
  #+END_SRC

  #+RESULTS:
  : xxx@myvm executed this block in the /home/xxx directory

- The block below will execute in =/ssh:xxx@myvm:/home/xxx/todolist1=

  #+BEGIN_SRC bash :dir (format "%s/todolist1" (replace-regexp-in-string ":dir +" "" (org-entry-get nil "HEADER-ARGS:bash" t)))
    echo "$USER@$HOSTNAME executed this block in the $PWD directory"
  #+END_SRC

  #+RESULTS:
  : xxx@myvm executed this block in the /home/xxx/todolist1 directory

- The block below will execute in =/ssh:xxx@myvm:/home/xxx/todolist2=

  #+BEGIN_SRC bash :dir (format "%s/todolist2" (replace-regexp-in-string ":dir +" "" (org-entry-get nil "HEADER-ARGS:bash" t)))
    echo "$USER@$HOSTNAME executed this block in the $PWD directory"
  #+END_SRC

  #+RESULTS:
  : xxx@myvm executed this block in the /home/xxx/todolist2 directory

The noweb functionality built into org-mode is amazingly useful!

  • Assign names to SRC blocks using #+NAME: or :new-ref headers.

    e.g. #+NAME: my-code or :noweb-ref my-code

  • SRC blocks with the same name become a single block when read in order from the top to bottom of the org file.

  • Names provide 2 new features inside other SRC blocks with the :noweb yes header.

    • Use <<my-code>> syntax to automatically embed code from blocks named my-code.

    • Use <<my-code()>> syntax to execute blocks named my-code and automatically embed the #+RESULTS: generated by the named block. As extra bonus, you can pass variables in the the () to the named blocks before execution.

  • Use the :tangle and :file headers to generate multiple files out and org file. As an added bonus, use :mkdir yes to automatically create missing subdirectories.

  • Mix and match these features to generate source code, config files, images and other forms human documentation from an org-mode file. In the past, I have generated 100+ customized files to build a project from a single org file.

Thanks for asking your question!


The code in this answer was tested using:
emacs version: GNU Emacs 25.2.1 (x86_64-unknown-cygwin, GTK+ Version 3.22.10)
org-mode version: 9.1.2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.