101-110-run2.rst 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. .. _run3:
  2. Input and output
  3. ----------------
  4. In the previous two sections, you created a simple ``.tsv`` file of all
  5. speakers and talk titles in the ``longnow/`` podcasts subdataset, and you have
  6. re-executed a :dlcmd:`run` command after a bug-fix in your script.
  7. But these previous :dlcmd:`run` and :dlcmd:`rerun` command were very simple.
  8. Maybe you noticed some values in the ``run record`` were empty:
  9. ``inputs`` and ``outputs`` for example did not have an entry. Let's experience
  10. a few situations in which
  11. these two arguments can become necessary.
  12. In our DataLad-101 course we were given a group assignment. Everyone should
  13. give a small presentation about an open DataLad dataset they found. Conveniently,
  14. you decided to settle for the longnow podcasts right away.
  15. After all, you know the dataset quite well already,
  16. and after listening to almost a third of the podcasts
  17. and enjoying them a lot,
  18. you also want to recommend them to the others.
  19. Almost all of the slides are ready, but what's still missing is the logo of the
  20. longnow podcasts. Good thing that this is part of the subdataset,
  21. so you can simply retrieve it from there.
  22. The logos (one for the SALT series, one for the Interval series -- the two
  23. directories in the subdataset)
  24. were originally extracted from the podcasts metadata information by DataLad.
  25. In a while, we will dive into the metadata aggregation capabilities of DataLad,
  26. but for now, let's just use the logos instead of finding out where they
  27. come from -- this will come later.
  28. As part of the metadata of the dataset, the logos are
  29. in the hidden paths
  30. ``.datalad/feed_metadata/logo_salt.jpg`` and
  31. ``.datalad/feed_metadata/logo_interval.jpg``:
  32. .. runrecord:: _examples/DL-101-110-101
  33. :language: console
  34. :workdir: dl-101/DataLad-101
  35. :notes: We saw a very simple datalad run. Now we are going to extend it with useful options. Narrative: prepare talk about dataset, add logo to slides. For this, we'll try to resize a logo in the meta data of the subdataset
  36. :cast: 02_reproducible_execution
  37. $ ls recordings/longnow/.datalad/feed_metadata/*jpg
  38. For the slides you decide to prepare images of size 400x400 px, but
  39. the logos' original size is much larger (both are 3000x3000 pixel). Therefore
  40. let's try to resize the images -- currently, they are far too large to fit on a slide.
  41. To resize an image from the command line we can use the Unix
  42. command ``convert -resize`` from the `ImageMagick tool <https://imagemagick.org/index.php>`_.
  43. The command takes a new size in pixels as an argument, a path to the file that should be
  44. resized, and a filename and path under which a new,
  45. resized image will be saved.
  46. To resize one image to 400x400 px, the command would thus be
  47. ``convert -resize 400x400 path/to/file.jpg path/to/newfilename.jpg``.
  48. .. index::
  49. pair: install ImageMagick; on Windows
  50. single: installation; ImageMagick
  51. .. windows-wit:: Tool installation
  52. .. include:: topic/installation-imagemagick.rst
  53. Remembering the last lecture on :dlcmd:`run`, you decide to plug this into
  54. :dlcmd:`run`. Even though this is not a script, it is a command, and you can wrap
  55. commands like this conveniently with :dlcmd:`run`.
  56. Because they will be quite long, we line break the commands in the upcoming examples
  57. for better readability -- in your terminal, you can always write the commands into
  58. a single line.
  59. .. index::
  60. pair: run command with provenance capture; with DataLad run
  61. .. runrecord:: _examples/DL-101-110-102
  62. :language: console
  63. :workdir: dl-101/DataLad-101
  64. :emphasize-lines: 4
  65. :notes: This command resizes the logo to 400 by 400 px -- but it will fail!
  66. :cast: 02_reproducible_execution
  67. :exitcode: 1
  68. $ datalad run -m "Resize logo for slides" \
  69. "convert -resize 400x400 recordings/longnow/.datalad/feed_metadata/logo_salt.jpg recordings/salt_logo_small.jpg"
  70. *Oh, crap!* Why didn't this work?
  71. Let's take a look at the error message DataLad provides. In general, these error messages
  72. might seem wordy, and maybe a bit intimidating as well, but usually they provide helpful
  73. information to find out what is wrong. Whenever you encounter an error message,
  74. make sure to read it, even if it feels like a mushroom cloud exploded in your terminal.
  75. A :dlcmd:`run` error message has several parts. The first starts after
  76. ``[INFO ] == Command start (output follows) =====``.
  77. This is displaying errors that the
  78. terminal command threw: The ``convert`` tool complains that it cannot open
  79. the file, because there is "No such file or directory".
  80. The second part starts after
  81. ``[INFO ] == Command exit (modification check follows) =====``.
  82. DataLad adds information about a "non-zero exit code". A non-zero exit code indicates
  83. that something went wrong [#f1]_. In principle, you could go ahead and google what this
  84. specific exit status indicates. However, the solution might have already occurred to you when
  85. reading the first error report: The file is not present.
  86. How can that be?
  87. "Right!", you exclaim with a facepalm.
  88. Just as the ``.mp3`` files, the ``.jpg`` file content is not present
  89. locally after a :dlcmd:`clone`, and we did not :dlcmd:`get` it yet!
  90. .. index::
  91. pair: declare command input; with DataLad run
  92. This is where the ``-i``/``--input`` option for a ``datalad run`` becomes useful.
  93. The content of everything that is specified as an ``input`` will be retrieved
  94. prior to running the command.
  95. .. runrecord:: _examples/DL-101-110-103
  96. :language: console
  97. :workdir: dl-101/DataLad-101
  98. :emphasize-lines: 8
  99. :realcommand: datalad run --input "recordings/longnow/.datalad/feed_metadata/logo_salt.jpg" "convert -resize 400x400 recordings/longnow/.datalad/feed_metadata/logo_salt.jpg recordings/salt_logo_small.jpg"
  100. :notes: The problem is that the content (logo) is not yet retrieved. The --input option makes sure that all content is retrieved prior to command execution.
  101. :cast: 02_reproducible_execution
  102. $ datalad run -m "Resize logo for slides" \
  103. --input "recordings/longnow/.datalad/feed_metadata/logo_salt.jpg" \
  104. "convert -resize 400x400 recordings/longnow/.datalad/feed_metadata/logo_salt.jpg recordings/salt_logo_small.jpg"
  105. $ # or shorter:
  106. $ datalad run -m "Resize logo for slides" \
  107. -i "recordings/longnow/.datalad/feed_metadata/logo_salt.jpg" \
  108. "convert -resize 400x400 recordings/longnow/.datalad/feed_metadata/logo_salt.jpg recordings/salt_logo_small.jpg"
  109. Cool! You can see in this output that prior to the data command execution, DataLad did a :dlcmd:`get`.
  110. This is useful for several reasons. For one, it saved us the work of manually
  111. getting content. But moreover, this is useful for anyone with whom we might share the
  112. dataset: With an installed dataset one can very simply rerun :dlcmd:`run` commands
  113. if they have the input argument appropriately specified. It is therefore good practice to
  114. specify the inputs appropriately. Remember from section :ref:`installds`
  115. that :dlcmd:`get` will only retrieve content if
  116. it is not yet present, all input already downloaded will not be downloaded again -- so
  117. specifying inputs even though they are already present will not do any harm.
  118. .. index::
  119. pair: path globbing; with DataLad run
  120. .. find-out-more:: What if there are several inputs?
  121. Often, a command needs several inputs. In principle, every input (which could be files, directories, or subdatasets) gets its own ``-i``/``--input``
  122. flag. However, you can make use of :term:`globbing`. For example,
  123. .. code-block:: console
  124. $ datalad run --input "*.jpg" "COMMAND"
  125. will retrieve all ``.jpg`` files prior to command execution.
  126. If outputs already exist...
  127. ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  128. .. index::
  129. pair: files are unlocked by default; on Windows
  130. pair: unlocked files; in adjusted mode
  131. .. windows-wit:: Good news! Here is something that is easier on Windows
  132. .. include:: topic/adjustedmode-unlockedfiles.rst
  133. Looking at the resulting image, you wonder whether 400x400 might be a tiny bit to small.
  134. Maybe we should try to resize it to 450x450, and see whether that looks better?
  135. Note that we cannot use a :dlcmd:`rerun` for this: if we want to change the dimension option
  136. in the command, we have to define a new :dlcmd:`run` command.
  137. To establish best-practices, let's specify the input even though it is already present:
  138. .. runrecord:: _examples/DL-101-110-104
  139. :language: console
  140. :workdir: dl-101/DataLad-101
  141. :emphasize-lines: 9
  142. :realcommand: datalad run --input "recordings/longnow/.datalad/feed_metadata/logo_salt.jpg" "convert -resize 450x450 recordings/longnow/.datalad/feed_metadata/logo_salt.jpg recordings/salt_logo_small.jpg"
  143. :notes: Maybe 400x400 is too small. We should try 450x450. Can we use a datalad rerun for this? (no)
  144. :exitcode: 1
  145. :cast: 02_reproducible_execution
  146. $ datalad run -m "Resize logo for slides" \
  147. --input "recordings/longnow/.datalad/feed_metadata/logo_salt.jpg" \
  148. "convert -resize 450x450 recordings/longnow/.datalad/feed_metadata/logo_salt.jpg recordings/salt_logo_small.jpg"
  149. $ # or shorter:
  150. $ datalad run -m "Resize logo for slides" \
  151. -i "recordings/longnow/.datalad/feed_metadata/logo_salt.jpg" \
  152. "convert -resize 450x450 recordings/longnow/.datalad/feed_metadata/logo_salt.jpg recordings/salt_logo_small.jpg"
  153. **Oh wtf**... *What is it now?*
  154. A quick glimpse into the error message shows a different error than before:
  155. The tool complains that it is "unable to open" the image, because the "Permission [is] denied".
  156. We have not seen anything like this before, and we need to turn to our lecturer for help.
  157. Confused about what we might have
  158. done wrong, we raise our hand to ask the instructor.
  159. Knowingly, she smiles, and tells you about how DataLad protects content given
  160. to it:
  161. "Content in your DataLad dataset is protected by :term:`git-annex` from
  162. accidental changes" our instructor begins.
  163. "Wait!" we interrupt. "First off, that wasn't accidental. And second, I was told this
  164. course does not have ``git-annex-101`` as a prerequisite?"
  165. "Yes, hear me out" she says. "I promise you two different solutions at
  166. the end of this explanation, and the concept behind this is quite relevant".
  167. DataLad usually gives content to :term:`git-annex` to store and track.
  168. git-annex, let's just say, takes this task *really* seriously. One of its
  169. features that you have just experienced is that it *locks* content.
  170. If files are *locked down*, their content cannot be modified. In principle,
  171. that's not a bad thing: It could be your late grandma's secret cherry-pie
  172. recipe, and you do not want to *accidentally* change that.
  173. Therefore, a file needs to be consciously *unlocked* to apply modifications.
  174. In the attempt to resize the image to 450x450 you tried to overwrite
  175. ``recordings/salt_logo_small.jpg``, a file that was given to DataLad
  176. and thus protected by git-annex.
  177. .. index::
  178. pair: unlock; DataLad command
  179. pair: unlock file; with DataLad
  180. There is a DataLad command that takes care of unlocking file content,
  181. and thus making locked files modifiable again: :dlcmd:`unlock`.
  182. Let us check out what it does:
  183. .. index::
  184. pair: files are unlocked by default; on Windows
  185. single: adjusted branch; unlocked files
  186. .. windows-wit:: What happens if I run this on Windows?
  187. .. include:: topic/adjustedmode-unlockedfiles2.rst
  188. .. runrecord:: _examples/DL-101-111-101
  189. :language: console
  190. :workdir: dl-101/DataLad-101
  191. :notes: The created output is protected from accidental modifications, we have to unlock it first:
  192. :cast: 02_reproducible_execution
  193. $ datalad unlock recordings/salt_logo_small.jpg
  194. Well, ``unlock(ok)`` does not sound too bad for a start. As always, we
  195. feel the urge to run a :dlcmd:`status` on this:
  196. .. runrecord:: _examples/DL-101-111-102
  197. :language: console
  198. :workdir: dl-101/DataLad-101
  199. :notes: How does the file look like after an unlock?
  200. :cast: 02_reproducible_execution
  201. $ datalad status
  202. "Ah, do not mind that for now", our instructor says, and with a wink she
  203. continues: "We'll talk about symlinks and object trees a while later".
  204. You are not really sure whether that's a good thing, but you have a task to focus
  205. on. Hastily, you run the command right from the terminal:
  206. .. runrecord:: _examples/DL-101-111-103
  207. :language: console
  208. :workdir: dl-101/DataLad-101
  209. :notes: In principle, you could rerun the command now, outside of any datalad run. The unlocked output can be overwritten
  210. :cast: 02_reproducible_execution
  211. $ convert -resize 450x450 recordings/longnow/.datalad/feed_metadata/logo_salt.jpg recordings/salt_logo_small.jpg
  212. Hey, no permission denied error! You note that the instructor still stands
  213. right next to you. "Sooo... now what do I do to *lock* the file again?" you ask.
  214. "Well... what you just did there was quite suboptimal. Didn't you want to
  215. use :dlcmd:`run`? But, anyway, in order to lock the file again, you would need to
  216. run a :dlcmd:`save`."
  217. .. runrecord:: _examples/DL-101-111-104
  218. :language: console
  219. :workdir: dl-101/DataLad-101
  220. :notes: Afterwards you'd need to save, to lock everything again
  221. :cast: 02_reproducible_execution
  222. $ datalad save -m "resized picture by hand"
  223. "So", you wonder aloud, "whenever I want to modify I need to
  224. :dlcmd:`unlock` it, do the modifications, and then :dlcmd:`save` it?"
  225. "Well, this is certainly one way of doing it, and a completely valid workflow
  226. if you would do that outside of a :dlcmd:`run` command.
  227. But within :dlcmd:`run` there is actually a much easier way of doing this.
  228. Let's use the ``--output`` argument."
  229. :dlcmd:`run` *retrieves* everything that is specified as ``--input`` prior to
  230. command execution, and it *unlocks* everything specified as ``--output`` prior to
  231. command execution. Therefore, whenever the output of a :dlcmd:`run` command already
  232. exists and is tracked, it should be specified as an argument in
  233. the ``-o``/``--output`` option.
  234. .. index::
  235. pair: path globbing; with DataLad run
  236. .. find-out-more:: But what if I have a lot of outputs?
  237. The use case here is simplistic -- a single file gets modified.
  238. But there are commands and tools that create full directories with
  239. many files as an output.
  240. The easiest way to specify this type of output
  241. is by supplying the directory name, or the directory name and a :term:`globbing` character, such as
  242. ``-o directory/*.dat``.
  243. This would unlock all files with a ``.dat`` extension inside of ``directory``.
  244. To glob for files in multiple levels of directories, use ``**`` (a so-called `globstar <https://www.linuxjournal.com/content/globstar-new-bash-globbing-option>`_) for a recursive glob through any number directories.
  245. And, just as for ``-i``/``--input``, you could use multiple ``--output`` specifications.
  246. .. index::
  247. pair: declare command output; with DataLad run
  248. In order to execute :dlcmd:`run` with both the ``-i``/``--input`` and ``-o``/``--output``
  249. flag and see their magic, let's crop the second logo, ``logo_interval.jpg``:
  250. .. index::
  251. pair: files are unlocked by default; on Windows
  252. pair: run; DataLad command
  253. pair: unlocked files; in adjusted mode
  254. .. windows-wit:: Wait, would I need to specify outputs, too?
  255. .. include:: topic/adjustedmode-unlockedfiles-output.rst
  256. .. runrecord:: _examples/DL-101-111-105
  257. :language: console
  258. :workdir: dl-101/DataLad-101
  259. :emphasize-lines: 11
  260. :realcommand: datalad run --input "recordings/longnow/.datalad/feed_metadata/logo_interval.jpg" --output "recordings/interval_logo_small.jpg" "convert -resize 450x450 recordings/longnow/.datalad/feed_metadata/logo_interval.jpg recordings/interval_logo_small.jpg"
  261. :notes: but it is way easier to just use the --output option of datalad run: it takes care of unlocking if necessary
  262. :cast: 02_reproducible_execution
  263. $ datalad run -m "Resize logo for slides" \
  264. --input "recordings/longnow/.datalad/feed_metadata/logo_interval.jpg" \
  265. --output "recordings/interval_logo_small.jpg" \
  266. "convert -resize 450x450 recordings/longnow/.datalad/feed_metadata/logo_interval.jpg recordings/interval_logo_small.jpg"
  267. $ # or shorter:
  268. $ datalad run -m "Resize logo for slides" \
  269. -i "recordings/longnow/.datalad/feed_metadata/logo_interval.jpg" \
  270. -o "recordings/interval_logo_small.jpg" \
  271. "convert -resize 450x450 recordings/longnow/.datalad/feed_metadata/logo_interval.jpg recordings/interval_logo_small.jpg"
  272. This time, with both ``--input`` and ``--output``
  273. options specified, DataLad informs about the :dlcmd:`get`
  274. operations it performs prior to the command
  275. execution, and :dlcmd:`run` executes the command successfully.
  276. It does *not* inform about any :dlcmd:`unlock` operation,
  277. because the output ``recordings/interval_logo_small.jpg`` does not
  278. exist before the command is run. Should you rerun this command however,
  279. the summary will include a statement about content unlocking. You will
  280. see an example of this in the next section.
  281. Note now how many individual commands a :dlcmd:`run` saves us:
  282. :dlcmd:`get`, :dlcmd:`unlock`, and :dlcmd:`save`!
  283. But even better: Beyond saving time *now*, running commands reproducibly and
  284. recorded with :dlcmd:`run` saves us plenty of time in the future as soon
  285. as we want to rerun a command, or find out how a file came into existence.
  286. With this last code snippet, you have experienced a full :dlcmd:`run` command: commit message,
  287. input and output definitions (the order in which you give those two options is irrelevant),
  288. and the command to be executed. Whenever a command takes input or produces output you should specify
  289. this with the appropriate option.
  290. Make a note of this behavior in your ``notes.txt`` file.
  291. .. runrecord:: _examples/DL-101-111-106
  292. :language: console
  293. :workdir: dl-101/DataLad-101
  294. :notes: Finally, lets add a note on this
  295. :cast: 02_reproducible_execution
  296. $ cat << EOT >> notes.txt
  297. You should specify all files that a command takes as input with an
  298. -i/--input flag. These files will be retrieved prior to the command
  299. execution. Any content that is modified or produced by the command
  300. should be specified with an -o/--output flag. Upon a run or rerun of
  301. the command, the contents of these files will get unlocked so that
  302. they can be modified.
  303. EOT
  304. Save yourself the preparation time
  305. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  306. Its generally good practice to specify ``--input`` and ``--output`` even if your input files are already retrieved and your output files unlocked -- it makes sure that a recomputation can succeed, even if inputs are not yet retrieved, or if output needs to be unlocked.
  307. However, the internal preparation steps of checking that inputs exist or that outputs are unlocked can take a bit of time, especially if it involves checking a large number of files.
  308. If you want to avoid the expense of unnecessary preparation steps you can make use of the ``--assume-ready`` argument of :dlcmd:`run`.
  309. Depending on whether your inputs are already retrieved, your outputs already unlocked (or not needed to be unlocked), or both, specify ``--assume-ready`` with the argument ``inputs``, ``outputs`` or ``both`` and save yourself a few seconds, without sacrificing the ability to rerun your command under conditions in which the preparation would be necessary.
  310. Placeholders
  311. ^^^^^^^^^^^^
  312. Just after writing the note, you had to relax your fingers a bit. "Man, this was
  313. so much typing. Not only did I need to specify the inputs and outputs, I also had
  314. to repeat all of these lengthy paths in the command line call..." you think.
  315. There is a neat little trick to spare you half of this typing effort, though: *Placeholders*
  316. for inputs and outputs. This is how it works:
  317. Instead of running
  318. .. code-block:: console
  319. $ datalad run -m "Resize logo for slides" \
  320. --input "recordings/longnow/.datalad/feed_metadata/logo_interval.jpg" \
  321. --output "recordings/interval_logo_small.jpg" \
  322. "convert -resize 450x450 recordings/longnow/.datalad/feed_metadata/logo_interval.jpg recordings/interval_logo_small.jpg"
  323. you could shorten this to
  324. .. code-block:: console
  325. :emphasize-lines: 4
  326. $ datalad run -m "Resize logo for slides" \
  327. --input "recordings/longnow/.datalad/feed_metadata/logo_interval.jpg" \
  328. --output "recordings/interval_logo_small.jpg" \
  329. "convert -resize 450x450 {inputs} {outputs}"
  330. The placeholder ``{inputs}`` will expand to the path given as ``--input``, and
  331. the placeholder ``{outputs}`` will expand to the path given as ``--output``.
  332. This means instead of writing the full paths in the command, you can simply reuse
  333. the ``--input`` and ``--output`` specification done before.
  334. .. index::
  335. pair: multiple command inputs; with DataLad run
  336. .. find-out-more:: What if I have multiple inputs or outputs?
  337. If multiple values are specified, e.g., as in
  338. .. code-block:: console
  339. $ datalad run -m "move a few files around" \
  340. --input "file1" --input "file2" --input "file3" \
  341. --output "directory_a/" \
  342. "mv {inputs} {outputs}"
  343. the values will be joined by a space like this:
  344. .. code-block:: console
  345. $ datalad run -m "move a few files around" \
  346. --input "file1" --input "file2" --input "file3" \
  347. --output "directory_a/" \
  348. "mv file1 file2 file3 directory_a/"
  349. The order of the values will match that order from the command line.
  350. If you use globs for input specification, as in
  351. .. code-block:: console
  352. $ datalad run -m "move a few files around" \
  353. --input "file*" \
  354. --output "directory_a/" \
  355. "mv {inputs} {outputs}"
  356. the globs will expanded in alphabetical order (like bash):
  357. .. code-block:: console
  358. $ datalad run -m "move a few files around" \
  359. --input "file1" --input "file2" --input "file3" \
  360. --output "directory_a/" \
  361. "mv file1 file2 file3 directory_a/"
  362. If the command only needs a subset of the inputs or outputs, individual values
  363. can be accessed with an integer index, e.g., ``{inputs[0]}`` for the very first
  364. input.
  365. .. index::
  366. pair: run command with curly brackets; with DataLad run
  367. .. find-out-more:: ... wait, what if I need a curly bracket in my 'datalad run' call?
  368. If your command call involves a ``{`` or ``}`` character, you will need to escape
  369. this brace character by doubling it, i.e., ``{{`` or ``}}``.
  370. .. index::
  371. pair: dry-run; with DataLad run
  372. .. _dryrun:
  373. Dry-running your run call
  374. ^^^^^^^^^^^^^^^^^^^^^^^^^
  375. :dlcmd:`run` commands can become confusing and long, especially when you make heavy use of placeholders or wrap a complex bash commands.
  376. To better anticipate what you will be running, or help debug a failed command, you can make use of the ``--dry-run`` flag of ``datalad run``.
  377. This option needs a mode specification (``--dry-run=basic`` or ``dry-run=command``), followed by the ``run`` command you want to execute, and it will decipher the commands elements:
  378. The mode ``command`` will display the command that is about to be ran.
  379. The mode ``basic`` will report a few important details about the execution:
  380. Apart from displaying the command that will be ran, you will learn *where* the command runs, what its *inputs* are (helpful if your ``--input`` specification includes a :term:`globbing` term), and what its *outputs* are.
  381. .. only:: adminmode
  382. Add a tag at the section end.
  383. .. runrecord:: _examples/DL-101-111-107
  384. :language: console
  385. :workdir: dl-101/DataLad-101
  386. $ git branch sct_input_and_output
  387. .. [#f1] In shell programming, commands exit with a specific code that indicates
  388. whether they failed, and if so, how. Successful commands have the exit code zero. All failures
  389. have exit codes greater than zero.