relpipe-data/examples.xml
branchv_0
changeset 244 d4f401b5f90c
parent 241 f71d300205b7
equal deleted inserted replaced
243:9c1d0c5ed599 244:d4f401b5f90c
    12 		<p>
    12 		<p>
    13 			All examples were tested in <a href="https://www.gnu.org/software/bash/">GNU Bash</a>.
    13 			All examples were tested in <a href="https://www.gnu.org/software/bash/">GNU Bash</a>.
    14 			But they should also work in other shells.
    14 			But they should also work in other shells.
    15 		</p>
    15 		</p>
    16 		
    16 		
    17 		<h2>relpipe-in-cli: Hello Wordl!</h2>
    17 		<m:skript jazyk="bash" výstup="xhtml"><![CDATA[
    18 		
    18 			echo "<ul>";
    19 		<p>
    19 			DIR=$(dirname "$XWG_STRANKA_SOUBOR");
    20 			Let's start with an obligatory Hello World example.
    20 			DIR="$DIR/../vstup"
    21 		</p>
    21 			cd "$DIR";
    22 		
    22 			# TODO: use XQuery? (but Grep and Bash are everywhere)
    23 		<m:pre jazyk="bash"><![CDATA[relpipe-in-cli generate "relation_from_cli" 3 \
    23 			for f in examples-*.xml; do
    24 	"a" "integer" \
    24 				grep -oP '(?<=<m:pořadí-příkladu>).*(?=</m:pořadí-příkladu>)' $f | tr \\n ' '
    25 	"b" "string" \
    25 				echo "<li><m:a href=\"${f//\.xml/}\">$(grep -oP '(?<=<nadpis>).*(?=</nadpis>)' $f)</m:a> – $(grep -oP '(?<=<perex>).+(?=</perex>)' $f)</li>";
    26 	"c" "boolean" \
    26 			done | sort | sed -E 's/^[0-9]+ //'
    27 	"1" "Hello" "true" \
    27 			echo "</ul>";
    28 	"2" "World!" "false"]]></m:pre>
    28 		]]></m:skript>
    29 	
       
    30 		<p>
       
    31 			This command generates relational data.
       
    32 			In order to see them, we need to convert them to some other format.
       
    33 			For now, we will use the "tabular" format and pipe relational data to the <code>relpipe-out-tabular</code>.
       
    34 		</p>
       
    35 		
       
    36 		<m:pre jazyk="bash"><![CDATA[relpipe-in-cli generate "relation_from_cli" 3 \
       
    37 		"a" "integer" \
       
    38 		"b" "string" \
       
    39 		"c" "boolean" \
       
    40 		"1" "Hello" "true" \
       
    41 		"2" "World!" "false" \
       
    42 	| relpipe-out-tabular]]></m:pre>
       
    43 	
       
    44 		<p>Output:</p>
       
    45 
       
    46 		<pre><![CDATA[relation_from_cli:
       
    47  ╭─────────────┬────────────┬─────────────╮
       
    48  │ a (integer) │ b (string) │ c (boolean) │
       
    49  ├─────────────┼────────────┼─────────────┤
       
    50  │           1 │ Hello      │        true │
       
    51  │           2 │ World!     │       false │
       
    52  ╰─────────────┴────────────┴─────────────╯
       
    53 Record count: 2
       
    54 ]]></pre>
       
    55 
       
    56 		<p>
       
    57 			The syntax is simple as we see above. We specify the name of the relation, number of attributes,
       
    58 			and then their definitions (names and types),
       
    59 			followed by the data.
       
    60 		</p>
       
    61 
       
    62 		<p>
       
    63 			A single stream may contain multiple relations:
       
    64 		</p>		
       
    65 		
       
    66 		<m:pre jazyk="bash"><![CDATA[(relpipe-in-cli generate a 1 x string hello; \
       
    67  relpipe-in-cli generate b 1 y string world) \
       
    68 	| relpipe-out-tabular]]></m:pre>
       
    69 			
       
    70 		<p>
       
    71 			Thus we can combine various commands or files and pass the result to a single relational output filter (<code>relpipe-out-tabular</code> in this case) and get:
       
    72 		</p>
       
    73 		
       
    74 		<pre><![CDATA[a:
       
    75  ╭────────────╮
       
    76  │ x (string) │
       
    77  ├────────────┤
       
    78  │ hello      │
       
    79  ╰────────────╯
       
    80 Record count: 1
       
    81 b:
       
    82  ╭────────────╮
       
    83  │ y (string) │
       
    84  ├────────────┤
       
    85  │ world      │
       
    86  ╰────────────╯
       
    87 Record count: 1]]></pre>
       
    88 		
       
    89 		<h2>relpipe-in-cli: STDIN</h2>
       
    90 		
       
    91 		<p>
       
    92 			The number of <abbr title="Command-line interface">CLI</abbr> arguments is limited and they are passed at once to the process.
       
    93 			So there is option to pass the values from STDIN instead of CLI arguments.
       
    94 			Values on STDIN are expected to be separated by the null-byte.
       
    95 			We can generate such data e.g. using <code>echo</code> and <code>tr</code> (or using <code>printf</code> or other commands):
       
    96 		</p>
       
    97 		
       
    98 		<m:pre jazyk="bash"><![CDATA[echo -e "1\nHello\ntrue\n2\nWorld\nfalse" \
       
    99 	| tr \\n \\0 \
       
   100 	| relpipe-in-cli generate-from-stdin relation_from_stdin 3 \
       
   101 		a integer \
       
   102 		b string \
       
   103 		c boolean \
       
   104 	| relpipe-out-tabular]]></m:pre>
       
   105 
       
   106 		<p>
       
   107 			The output is same as above.
       
   108 			We can use this approach to convert various formats to relational data.
       
   109 			There are lot of data already in the form of null-separated values e.g. the process arguments:
       
   110 		</p>
       
   111 		
       
   112 		<m:pre jazyk="bash"><![CDATA[cat /proc/$(pidof mc)/cmdline \
       
   113 	| relpipe-in-cli generate-from-stdin mc_args 1 a string \
       
   114 	| relpipe-out-tabular
       
   115 ]]></m:pre>
       
   116 	
       
   117 		<p>If we have <code>mc /etc/ /tmp/</code> running in some other terminal, the output will be:</p>
       
   118 		
       
   119 		<pre><![CDATA[mc_args:
       
   120  ╭────────────╮
       
   121  │ a (string) │
       
   122  ├────────────┤
       
   123  │ mc         │
       
   124  │ /etc/      │
       
   125  │ /tmp/      │
       
   126  ╰────────────╯
       
   127 Record count: 3]]></pre>
       
   128 
       
   129 		<p>
       
   130 			Also the <code>find</code> command can produce data separated by the null-byte:
       
   131 		</p>
       
   132 		
       
   133 		<m:pre jazyk="bash"><![CDATA[find /etc/ -name '*ssh*_*' -print0 \
       
   134 	| relpipe-in-cli generate-from-stdin files 1 file_name string \
       
   135 	| relpipe-out-tabular]]></m:pre>
       
   136 	
       
   137 		<p>Will display something like this:</p>
       
   138 		
       
   139 		<pre><![CDATA[files:
       
   140  ╭───────────────────────────────────╮
       
   141  │ file_name                (string) │
       
   142  ├───────────────────────────────────┤
       
   143  │ /etc/ssh/ssh_host_ecdsa_key       │
       
   144  │ /etc/ssh/sshd_config              │
       
   145  │ /etc/ssh/ssh_host_ed25519_key.pub │
       
   146  │ /etc/ssh/ssh_host_ecdsa_key.pub   │
       
   147  │ /etc/ssh/ssh_host_rsa_key         │
       
   148  │ /etc/ssh/ssh_config               │
       
   149  │ /etc/ssh/ssh_host_ed25519_key     │
       
   150  │ /etc/ssh/ssh_import_id            │
       
   151  │ /etc/ssh/ssh_host_rsa_key.pub     │
       
   152  ╰───────────────────────────────────╯
       
   153 Record count: 9]]></pre>
       
   154 		
       
   155 		
       
   156 		<h2>relpipe-in-fstab</h2>
       
   157 		
       
   158 		<p>
       
   159 			Using command <code>relpipe-in-fstab</code> we can convert the <code>/etc/fstab</code> or <code>/etc/mtab</code> to relational data 
       
   160 		</p>
       
   161 		
       
   162 		<m:pre jazyk="bash"><![CDATA[relpipe-in-fstab | relpipe-out-tabular]]></m:pre>
       
   163 		
       
   164 		<p>
       
   165 			and see them as a nice table:
       
   166 		</p>
       
   167 		
       
   168 		<pre><![CDATA[fstab:
       
   169  ╭─────────────────┬──────────────────────────────────────┬──────────────────────┬───────────────┬───────────────────────────────────────┬────────────────┬────────────────╮
       
   170  │ scheme (string) │ device                      (string) │ mount_point (string) │ type (string) │ options                      (string) │ dump (integer) │ pass (integer) │
       
   171  ├─────────────────┼──────────────────────────────────────┼──────────────────────┼───────────────┼───────────────────────────────────────┼────────────────┼────────────────┤
       
   172  │ UUID            │ 29758270-fd25-4a6c-a7bb-9a18302816af │ /                    │ ext4          │ relatime,user_xattr,errors=remount-ro │              0 │              1 │
       
   173  │                 │ /dev/sr0                             │ /media/cdrom0        │ udf,iso9660   │ user,noauto                           │              0 │              0 │
       
   174  │                 │ /dev/sde                             │ /mnt/data            │ ext4          │ relatime,user_xattr,errors=remount-ro │              0 │              2 │
       
   175  │ UUID            │ a2b5f230-a795-4f6f-a39b-9b57686c86d5 │ /home                │ btrfs         │ relatime                              │              0 │              2 │
       
   176  │                 │ /dev/mapper/sdf_crypt                │ /mnt/private         │ xfs           │ relatime                              │              0 │              2 │
       
   177  ╰─────────────────┴──────────────────────────────────────┴──────────────────────┴───────────────┴───────────────────────────────────────┴────────────────┴────────────────╯
       
   178 Record count: 5]]></pre>
       
   179 
       
   180 		<p>And we can do the same also with a remote <code>fstab</code> or <code>mtab</code>; just by adding <code>ssh</code> to the pipeline:</p>
       
   181 
       
   182 		<m:pre jazyk="bash"><![CDATA[ssh example.com cat /etc/mtab | relpipe-in-fstab | relpipe-out-tabular]]></m:pre>
       
   183 		
       
   184 		<p>
       
   185 			The <code>cat</code> runs remotely. The <code>relpipe-in-fstab</code> and <code>relpipe-out-tabular</code> run on our machine.
       
   186 		</p>
       
   187 		
       
   188 		<p>
       
   189 			n.b. the <code>relpipe-in-fstab</code> reads the <code>/etc/fstab</code> if executed on TTY. Otherwise, it reads the STDIN.
       
   190 		</p>
       
   191 		
       
   192 		<h2>relpipe-out-xml</h2>
       
   193 		
       
   194 		<p>
       
   195 			Relational data can be converted to various formats and one of them is the XML.
       
   196 			This is a good option for further processing e.g. using XSLT transformation or passing the XML data to some other tool.
       
   197 			Just use <code>relpipe-out-xml</code> instead of <code>relpipe-out-tabular</code> and the rest of the pipeline remains unchanged:
       
   198 		</p>
       
   199 		
       
   200 		<m:pre jazyk="bash"><![CDATA[ssh example.com cat /etc/mtab | relpipe-in-fstab | relpipe-out-xml]]></m:pre>
       
   201 		
       
   202 		<p>
       
   203 			Will produce XML like this:
       
   204 		</p>
       
   205 		
       
   206 		<m:pre jazyk="xml" src="examples/relpipe-out-fstab.xml"/>
       
   207 
       
   208 		<p>
       
   209 			Thanks to XSLT, this XML can be easily converted e.g. to an XHTML table (<code>table|tr|td</code>) or other format.
       
   210 			Someone can convert such data to a (La)TeX table.
       
   211 		</p>
       
   212 		
       
   213 		<p>
       
   214 			n.b. the format is not final and will change i future versions (XML namespace, more metadata etc.).
       
   215 		</p>
       
   216 		
       
   217 		
       
   218 		<h2>relpipe-tr-validator</h2>
       
   219 		
       
   220 		<p>
       
   221 			Just a passthrough command, so these pipelines should produce the same hash:
       
   222 		</p>
       
   223 		
       
   224 		<m:pre jazyk="bash"><![CDATA[
       
   225 relpipe-in-fstab | relpipe-tr-validator | sha512sum
       
   226 relpipe-in-fstab | sha512sum]]></m:pre>
       
   227 
       
   228 		<p>
       
   229 			This tool can be used for testing whether a file contains valid relational data:
       
   230 		</p>
       
   231 		
       
   232 		<m:pre jazyk="bash"><![CDATA[
       
   233 if relpipe-tr-validator < "some-file.rp" &> /dev/null; then
       
   234 	echo "valid relational data";
       
   235 else
       
   236 	echo "garbage";
       
   237 fi]]></m:pre>
       
   238 		
       
   239 		<p>or as a one-liner:</p>
       
   240 		
       
   241 		<m:pre jazyk="bash"><![CDATA[relpipe-tr-validator < "some-file.rp" &> /dev/null && echo "ok" || echo "error"]]></m:pre>
       
   242 		
       
   243 		<p>
       
   244 			If an error is found, it is reported on STDERR. So just omit the <code>&amp;</code> in order to see the error message.
       
   245 		</p>
       
   246 		
       
   247 		
       
   248 		<h2>/etc/fstab formatting using -in-fstab, -out-nullbyte, xargs and Perl</h2>
       
   249 		
       
   250 		<p>
       
   251 			As we have seen before, we can convert <code>/etc/fstab</code> (or <code>mtab</code>)
       
   252 			to e.g. an XML or a nice and colorful table using <m:name/>.
       
   253 			But we can also convert these data back to the <code>fstab</code> format. And do it with proper indentation/padding.
       
   254 			Fstab has a simple format where values are separated by one or more whitespace characters.
       
   255 			But without proper indentation, these files look a bit obfuscated and hard to read (however, they are valid).
       
   256 		</p>
       
   257 		
       
   258 		<m:pre jazyk="text" src="examples/relpipe-out-fstab.txt"/>
       
   259 		
       
   260 		<p>
       
   261 			So let's build a pipeline that reformats the <code>fstab</code> and makes it more readable.
       
   262 		</p>
       
   263 			
       
   264 		<m:pre jazyk="bash">relpipe-in-fstab | relpipe-out-fstab &gt; reformatted-fstab.txt</m:pre>
       
   265 			
       
   266 		<p>
       
   267 			We can hack together a script called <code>relpipe-out-fstab</code> that accepts relational data and produces <code>fstab</code> data.
       
   268 			Later this will be probably implemented as a regular tool, but for now, it is just an example of a ad-hoc shell script:
       
   269 		</p>
       
   270 		
       
   271 		<m:pre jazyk="bash" src="examples/relpipe-out-fstab.sh" odkaz="ano"/>
       
   272 		
       
   273 		<p>
       
   274 			In the first part, we prepend a single record (<code>relpipe-in-cli</code>) before the data coming from STDIN (<code>cat</code>).
       
   275 			Then, we use <code>relpipe-out-nullbyte</code> to convert relational data to values separated by a null-byte.
       
   276 			This command processes only attribute values (skips relation and attribute names).
       
   277 			Then we used <code>xargs</code> to read the null-separated values and execute a Perl command for each record (pass to it a same number of arguments, as we have attributes: <code>--max-args=7</code>).
       
   278 			Perl does the actual formatting: adds padding and does some little tunning (merges two attributes and replaces empty values with <em>none</em>).
       
   279 		</p>
       
   280 		
       
   281 		<p>This is formatted version of the <code>fstab</code> above:</p>
       
   282 		
       
   283 		<m:pre jazyk="text" src="examples/relpipe-out-fstab.formatted.txt"/>
       
   284 		
       
   285 		<p>
       
   286 			And using following command we can verify, that the files differ only in comments and whitespace:
       
   287 		</p>
       
   288 		
       
   289 		<pre>relpipe-in-fstab | relpipe-out-fstab | diff -w /etc/fstab -</pre>
       
   290 
       
   291 		<p>
       
   292 			Another check (should print same hashes):
       
   293 		</p>
       
   294 		
       
   295 		<pre><![CDATA[relpipe-in-fstab | sha512sum 
       
   296 relpipe-in-fstab | relpipe-out-fstab | relpipe-in-fstab | sha512sum]]></pre>
       
   297 		
       
   298 		<p>
       
   299 			Regular implementation of <code>relpipe-out-fstab</code> will probably keep the comments
       
   300 			(it needs also one more attribute and small change in <code>relpipe-in-fstab</code>).
       
   301 		</p>
       
   302 		
       
   303 		<p>
       
   304 			For just mere <code>fstab</code> reformatting, this approach is a bit overengineering.
       
   305 			We could skip the whole relational thing and do just something like this:
       
   306 		</p>
       
   307 		
       
   308 		<m:pre jazyk="bash">cat /etc/fstab | grep -v '^#' | sed -E 's/\s+/\n/g' | tr \\n \\0 | xargs -0 -n7 ...</m:pre>
       
   309 		
       
   310 		<p>
       
   311 			plus prepend the comment (or do everything in Perl).
       
   312 			But this example is intended as a demostration, how we can
       
   313 			1) prepend some additional data before the data from STDIN
       
   314 			2) use <m:name/> and traditional tools like <code>xargs</code> or <code>perl</code> together.
       
   315 			And BTW we have implemented a (simple but working) <em>relpipe output filter</em> – and did it without any serious programming, just put some existing commands together :-)
       
   316 		</p>
       
   317 		
       
   318 		<blockquote>
       
   319 			<p>
       
   320 				There is more Unix-nature in one line of shell script than there is in ten thousand lines of C.
       
   321 				<m:podČarou>see <a href="http://www.catb.org/~esr/writings/unix-koans/ten-thousand.html">Master Foo and the Ten Thousand Lines</a></m:podČarou>
       
   322 			</p>
       
   323 		</blockquote>
       
   324 		
       
   325 		<h2>Writing an output filter in Bash</h2>
       
   326 		
       
   327 		<p>
       
   328 			In previous example we created an output filter in Perl. 
       
   329 			We converted a relation to values separated by <code>\0</code> and then passed it through <code>xargs</code> to a perl <em>one-liner</em> (or a <em>multi-liner</em> in this case).
       
   330 			But we can write such output filter in pure Bash without <code>xargs</code> and <code>perl</code>.
       
   331 			Of course, it is still limited to a single relation (or it can process multiple relations of same type and do something like implicit <code>UNION ALL</code>).
       
   332 		</p>
       
   333 		
       
   334 		<p>
       
   335 			We will define a function that will help us with reading the <code>\0</code>-separated values and putting them into shell variables:
       
   336 		</p>
       
   337 		
       
   338 		<m:pre jazyk="bash"><![CDATA[read_nullbyte() { for v in "$@"; do export "$v"; read -r -d '' "$v"; done }]]></m:pre>
       
   339 		
       
   340 		<!--
       
   341 			This version will not require the last \0:
       
   342 				read_zero() { for v in "$@"; do export "$v"; read -r -d '' "$v" || [ ! -z "${!v}" ]; done }
       
   343 			at least in case when the last value is not missing.
       
   344 			Other values might be null/missing: \0\0 is OK.
       
   345 		-->
       
   346 		
       
   347 		<p>
       
   348 			Currently, there is no known way how to do this without a custom function (just with <code>read</code> built-in command of Bash and its parameters).
       
   349 			But it is just a single line function, so not a big deal.
       
   350 		</p>
       
   351 		
       
   352 		<p>
       
   353 			And then we just read the values, put them in shell variables and process them in a cycle in a shell block of code:
       
   354 		</p>
       
   355 		
       
   356 		<m:pre jazyk="bash"><![CDATA[relpipe-in-fstab \
       
   357 	| relpipe-out-nullbyte \
       
   358 	| while read_nullbyte scheme device mount_point fs_type options dump pass; do
       
   359 		echo "Device ${scheme:+$scheme=}$device is mounted" \
       
   360 		     "at $mount_point and contains $fs_type.";
       
   361 	done]]></m:pre>
       
   362 	
       
   363 		<p>
       
   364 			Which will print:
       
   365 		</p>
       
   366 		
       
   367 		<pre><![CDATA[Device UUID=29758270-fd25-4a6c-a7bb-9a18302816af is mounted at / and contains ext4.
       
   368 Device /dev/sr0 is mounted at /media/cdrom0 and contains udf,iso9660.
       
   369 Device /dev/sde is mounted at /mnt/data and contains ext4.
       
   370 Device UUID=a2b5f230-a795-4f6f-a39b-9b57686c86d5 is mounted at /home and contains btrfs.
       
   371 Device /dev/mapper/sdf_crypt is mounted at /mnt/private and contains xfs.]]></pre>
       
   372 
       
   373 		<p>
       
   374 			Using this method, we can convert any single relation to any format (preferably some text one, but <code>printf</code> can produce also binary data).
       
   375 			This is good for ad-hoc conversions and single-relation data.
       
   376 			More powerful tools can be written in C++ and other languages like Java, Python, Guile etc. (when particular libraries are available).
       
   377 		</p>
       
   378 		
       
   379 		<h2>Rename VG in /etc/fstab using relpipe-tr-sed</h2>
       
   380 		
       
   381 		<p>
       
   382 			Assume that we have an <code>/etc/fstab</code> with many lines defining the mount-points (directories) of particular devices (disks) and we are using LVM.
       
   383 			If we rename a volume group (VG), we have to change all of them. The lines look like this one:
       
   384 		</p>
       
   385 		
       
   386 		<pre>/dev/alpha/photos    /mnt/photos/    btrfs    noauto,noatime,nodiratime    0  0</pre>
       
   387 		
       
   388 		<p>
       
   389 			We want to change all lines from <code>alpha</code> to <code>beta</code> (the new VG name).
       
   390 			This can be done by the power of regular expressions<m:podČarou>see <a href="https://en.wikibooks.org/wiki/Regular_Expressions/Simple_Regular_Expressions">Regular Expressions</a> at Wikibooks</m:podČarou> and this pipeline:
       
   391 		</p>
       
   392 		
       
   393 		<m:pre jazyk="bash"><![CDATA[relpipe-in-fstab \
       
   394 	| relpipe-tr-sed 'fstab' 'device' '^/dev/alpha/' '/dev/beta/' \
       
   395 	| relpipe-out-fstab]]></m:pre>
       
   396 	
       
   397 		<p>
       
   398 			The <code>relpipe-tr-sed</code> tool works only with given relation (<code>fstab</code>) and given attribute (<code>device</code>)
       
   399 			and it would leave untouched other relations and attributes in the stream.
       
   400 			So it would not replace the strings on unwanted places (if there are any random matches).
       
   401 		</p>
       
   402 		
       
   403 		<p>
       
   404 			Even the relation names and attribute names are specified as a regular expression, so we can (purposefully) modify multiple relations or attributes.
       
   405 			For example we can put zeroes in both <code>dump</code> and <code>pass</code> attributes:
       
   406 		</p>
       
   407 		
       
   408 		<m:pre jazyk="bash"><![CDATA[relpipe-in-fstab | relpipe-tr-sed 'fstab' 'dump|pass' '.+' '0' | relpipe-out-fstab]]></m:pre>
       
   409 		
       
   410 		<p>
       
   411 			n.b. the data types must be respected, we can not e.g. put <code>abc</code> in the <code>pass</code> attribute because it is declared as <code>integer</code>.
       
   412 		</p>
       
   413 		
       
   414 		<h2>Using relpipe-tr-sed with groups and backreferences</h2>
       
   415 		
       
   416 		<p>
       
   417 			This tool also support regex groups and backreferences. Thus we can use parts of the matched string in our replacement string:
       
   418 		</p>
       
   419 		
       
   420 		<m:pre jazyk="bash"><![CDATA[relpipe-in-cli generate r 1 a string "some string xxx_123 some zzz_456 other" \
       
   421 	| relpipe-tr-sed 'r' 'a' '([a-z]{3})_([0-9]+)' '$2:$1' \
       
   422 	| relpipe-out-tabular]]></m:pre>
       
   423 		
       
   424 		<p>Which would convert this:</p>
       
   425 		<pre><![CDATA[r:
       
   426  ╭────────────────────────────────────────╮
       
   427  │ a                             (string) │
       
   428  ├────────────────────────────────────────┤
       
   429  │ some string xxx_123 some zzz_456 other │
       
   430  ╰────────────────────────────────────────╯
       
   431 Record count: 1]]></pre>
       
   432 		
       
   433 		<p>into this:</p>
       
   434 		<pre><![CDATA[r:
       
   435  ╭────────────────────────────────────────╮
       
   436  │ a                             (string) │
       
   437  ├────────────────────────────────────────┤
       
   438  │ some string 123:xxx some 456:zzz other │
       
   439  ╰────────────────────────────────────────╯
       
   440 Record count: 1]]></pre>
       
   441 
       
   442 		<p>
       
   443 			If there were any other relations or attributes in the stream, they would be unaffected by this transformation,
       
   444 			becase we specified <code>'r' 'a'</code> instead of some wider regular expression that would match more relations or attributes.
       
   445 		</p>
       
   446 		
       
   447 		<h2>Filter /etc/fstab using relpipe-tr-grep</h2>
       
   448 		
       
   449 		<p>
       
   450 			If we are interested only in certain records in some relation, we can filter it using <code>relpipe-tr-grep</code>.
       
   451 			If we want to list e.g. only Btrfs and XFS file systems from our <code>fstab</code> (see above), we will run:
       
   452 		</p>
       
   453 		
       
   454 		
       
   455 		<m:pre jazyk="bash"><![CDATA[relpipe-in-fstab | relpipe-tr-grep 'fstab' 'type' 'btrfs|xfs' | relpipe-out-tabular]]></m:pre>
       
   456 				
       
   457 		<p>and we will get following filtered result:</p>
       
   458 		<pre><![CDATA[fstab:
       
   459  ╭─────────────────┬──────────────────────────────────────┬──────────────────────┬───────────────┬──────────────────┬────────────────┬────────────────╮
       
   460  │ scheme (string) │ device                      (string) │ mount_point (string) │ type (string) │ options (string) │ dump (integer) │ pass (integer) │
       
   461  ├─────────────────┼──────────────────────────────────────┼──────────────────────┼───────────────┼──────────────────┼────────────────┼────────────────┤
       
   462  │ UUID            │ a2b5f230-a795-4f6f-a39b-9b57686c86d5 │ /home                │ btrfs         │ relatime         │              0 │              2 │
       
   463  │                 │ /dev/mapper/sdf_crypt                │ /mnt/private         │ xfs           │ relatime         │              0 │              2 │
       
   464  ╰─────────────────┴──────────────────────────────────────┴──────────────────────┴───────────────┴──────────────────┴────────────────┴────────────────╯
       
   465 Record count: 2]]></pre>
       
   466 
       
   467 		<p>
       
   468 			Command arguments are similar to <code>relpipe-tr-sed</code>.
       
   469 			Everything is a regular expression.
       
   470 			Only relations matching the regex will be filtered, others will flow through the pipeline unmodified.
       
   471 			If the attribute regex matches more attribute names, filtering will be done with logical OR
       
   472 			i.e. the record is included if at least one of that attributes matches the search regex.
       
   473 		</p>
       
   474 		
       
   475 		<p>
       
   476 			If we need exact match of the whole attribute, we have to use something like <code>'^btrfs|xfs$'</code>,
       
   477 			otherwise mere substring-match is enough to include the record.
       
   478 		</p>
       
   479 		
       
   480 		<h2>SELECT mount_point FROM fstab WHERE type IN ('btrfs', 'xfs')</h2>
       
   481 		
       
   482 		<p>
       
   483 			While reading classic pipelines involving <code>grep</code> and <code>cut</code> commands
       
   484 			we must notice that there is some similarity with simple SQL queries looking like:
       
   485 		</p>
       
   486 		
       
   487 		<m:pre jazyk="SQL">SELECT "some", "cut", "fields" FROM stdin WHERE grep_matches(whole_line);</m:pre>
       
   488 		
       
   489 		<p>
       
   490 			And that is true: <code>grep</code> does restriction<m:podČarou>
       
   491 				<a href="https://en.wikipedia.org/wiki/Selection_(relational_algebra)">selecting</a> only certain records from the original relation according to their match with given conditions</m:podČarou>
       
   492 			and <code>cut</code> does projection<m:podČarou>limited subset of what <a href="https://en.wikipedia.org/wiki/Projection_(relational_algebra)">projection</a> means</m:podČarou>.
       
   493 			Now we can do these relational operations using our relational tools called <code>relpipe-tr-grep</code> and <code>relpipe-tr-cut</code>.
       
   494 		</p>
       
   495 		
       
   496 		<p>
       
   497 			Assume that we need only <code>mount_point</code> fields from our <code>fstab</code> where <code>type</code> is <code>btrfs</code> or <code>xfs</code>
       
   498 			and we want to do something (a shell script block) with these directory paths.
       
   499 		</p>
       
   500 		
       
   501 		<m:pre jazyk="bash"><![CDATA[relpipe-in-fstab \
       
   502 	| relpipe-tr-grep 'fstab' 'type' '^btrfs|xfs$' \
       
   503 	| relpipe-tr-cut 'fstab' 'mount_point' \
       
   504 	| relpipe-out-nullbyte \
       
   505 	| while read -r -d '' m; do
       
   506 		echo "$m";
       
   507 	done]]></m:pre>
       
   508 	
       
   509 		<p>
       
   510 			The <code>relpipe-tr-cut</code> tool has similar syntax to its <em>grep</em> and <em>sed</em> siblings and also uses the power of regular expressions.
       
   511 			In this case it modifies on-the-fly the <code>fstab</code> relation and drops all its attributes except the <code>mount_point</code> one.
       
   512 		</p>
       
   513 		
       
   514 		<p>
       
   515 			Then we pass the data to the Bash <code>while</code> cycle.
       
   516 			In such simple scenario (just <code>echo</code>), we could use <code>xargs</code> as in examples above,
       
   517 			but in this syntax, we can write whole block of shell commands for each record/value and do more complex actions with them.
       
   518 		</p>
       
   519 		
       
   520 		<h2>More projections with relpipe-tr-cut</h2>
       
   521 		
       
   522 		<p>
       
   523 			Assume that we have a simple relation containing numbers:
       
   524 		</p>
       
   525 	
       
   526 		<m:pre jazyk="bash"><![CDATA[seq 0 8 \
       
   527 	| tr \\n \\0 \
       
   528 	| relpipe-in-cli generate-from-stdin numbers 3 a integer b integer c integer \
       
   529 	> numbers.rp]]></m:pre>
       
   530 
       
   531 		<p>and second one containing letters:</p>
       
   532 
       
   533 		<m:pre jazyk="bash"><![CDATA[relpipe-in-cli generate letters 2 a string b string A B C D > letters.rp]]></m:pre>
       
   534 
       
   535 		<p>We saved them into two files and then combined them into a single file. We will work with them as they are a single stream of relations:</p>
       
   536 		
       
   537 		<m:pre jazyk="bash"><![CDATA[cat numbers.rp letters.rp > both.rp;
       
   538 cat both.rp | relpipe-out-tabular]]></m:pre>
       
   539 		
       
   540 		<p>Will print:</p>
       
   541 		
       
   542 		<pre><![CDATA[numbers:
       
   543  ╭─────────────┬─────────────┬─────────────╮
       
   544  │ a (integer) │ b (integer) │ c (integer) │
       
   545  ├─────────────┼─────────────┼─────────────┤
       
   546  │           0 │           1 │           2 │
       
   547  │           3 │           4 │           5 │
       
   548  │           6 │           7 │           8 │
       
   549  ╰─────────────┴─────────────┴─────────────╯
       
   550 Record count: 3
       
   551 letters:
       
   552  ╭─────────────┬─────────────╮
       
   553  │ a  (string) │ b  (string) │
       
   554  ├─────────────┼─────────────┤
       
   555  │ A           │ B           │
       
   556  │ C           │ D           │
       
   557  ╰─────────────┴─────────────╯
       
   558 Record count: 2]]></pre>
       
   559 
       
   560 		<p>We can put away the <code>a</code> attribute from the <code>numbers</code> relation:</p>
       
   561 		
       
   562 		<m:pre jazyk="bash">cat both.rp | relpipe-tr-cut 'numbers' 'b|c' | relpipe-out-tabular</m:pre>
       
   563 		
       
   564 		<p>and leave the <code>letters</code> relation unaffected:</p>
       
   565 		
       
   566 		<pre><![CDATA[numbers:
       
   567  ╭─────────────┬─────────────╮
       
   568  │ b (integer) │ c (integer) │
       
   569  ├─────────────┼─────────────┤
       
   570  │           1 │           2 │
       
   571  │           4 │           5 │
       
   572  │           7 │           8 │
       
   573  ╰─────────────┴─────────────╯
       
   574 Record count: 3
       
   575 letters:
       
   576  ╭─────────────┬─────────────╮
       
   577  │ a  (string) │ b  (string) │
       
   578  ├─────────────┼─────────────┤
       
   579  │ A           │ B           │
       
   580  │ C           │ D           │
       
   581  ╰─────────────┴─────────────╯
       
   582 Record count: 2]]></pre>
       
   583 
       
   584 		<p>Or we can remove <code>a</code> from both relations resp. keep there only attributes whose names match <code>'b|c'</code> regex:</p>
       
   585 
       
   586 		<m:pre jazyk="bash">cat both.rp | relpipe-tr-cut '.*' 'b|c' | relpipe-out-tabular</m:pre>
       
   587 		
       
   588 		<p>Instead of <code>'.*'</code> we could use <code>'numbers|letters'</code> and in this case it will give the same result:</p>
       
   589 		
       
   590 		<pre><![CDATA[numbers:
       
   591  ╭─────────────┬─────────────╮
       
   592  │ b (integer) │ c (integer) │
       
   593  ├─────────────┼─────────────┤
       
   594  │           1 │           2 │
       
   595  │           4 │           5 │
       
   596  │           7 │           8 │
       
   597  ╰─────────────┴─────────────╯
       
   598 Record count: 3
       
   599 letters:
       
   600  ╭─────────────╮
       
   601  │ b  (string) │
       
   602  ├─────────────┤
       
   603  │ B           │
       
   604  │ D           │
       
   605  ╰─────────────╯
       
   606 Record count: 2]]></pre>
       
   607 
       
   608 		<p>All the time, we are reducing the attributes. But we can also multiply them or change their order:</p>
       
   609 		
       
   610 		<m:pre jazyk="bash">cat both.rp | relpipe-tr-cut 'numbers' 'b|a|c' 'b' 'a' 'a' | relpipe-out-tabular</m:pre>
       
   611 		
       
   612 		<p>
       
   613 			n.b. the order in <code>'b|a|c'</code> does not matter and if such regex matches, it preserves the original order of the attributes;
       
   614 			but if we use multiple regexes to specify attributes, their order and count matters:
       
   615 		</p>
       
   616 		
       
   617 		<pre><![CDATA[numbers:
       
   618  ╭─────────────┬─────────────┬─────────────┬─────────────┬─────────────┬─────────────╮
       
   619  │ a (integer) │ b (integer) │ c (integer) │ b (integer) │ a (integer) │ a (integer) │
       
   620  ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
       
   621  │           0 │           1 │           2 │           1 │           0 │           0 │
       
   622  │           3 │           4 │           5 │           4 │           3 │           3 │
       
   623  │           6 │           7 │           8 │           7 │           6 │           6 │
       
   624  ╰─────────────┴─────────────┴─────────────┴─────────────┴─────────────┴─────────────╯
       
   625 Record count: 3
       
   626 letters:
       
   627  ╭─────────────┬─────────────╮
       
   628  │ a  (string) │ b  (string) │
       
   629  ├─────────────┼─────────────┤
       
   630  │ A           │ B           │
       
   631  │ C           │ D           │
       
   632  ╰─────────────┴─────────────╯
       
   633 Record count: 2]]></pre>
       
   634 
       
   635 		<p>
       
   636 			The <code>letters</code> relation stays rock steady and <code>relpipe-tr-cut 'numbers'</code> does not affect it in any way.
       
   637 		</p>
       
   638 		
       
   639 		
       
   640 		<h2>Read an Atom feed using XQuery and relpipe-in-xml</h2>
       
   641 		
       
   642 		<p>
       
   643 			Atom Syndication Format is a standard for publishing web feeds a.k.a web syndication. 
       
   644 			These feeds are usually consumed by a <em>feed reeder</em> that aggregates news from many websites and displays them in a uniform format.
       
   645 			The Atom feed is an XML with a list of recent news containing their titles, URLs and short annotations.
       
   646 			It also contains some metadata (website author, title etc.).
       
   647 		</p>
       
   648 		<p>
       
   649 			Using this simple XQuery<m:podČarou>see <a href="https://en.wikibooks.org/wiki/XQuery">XQuery</a> at Wikibooks</m:podČarou>
       
   650 			<em>FLWOR Expression</em>
       
   651 			we convert the Atom feed into the XML serialization of relational data:
       
   652 		</p>
       
   653 		
       
   654 		<m:pre jazyk="xq" src="examples/atom.xq" odkaz="ano"/>
       
   655 		
       
   656 		<p>
       
   657 			This is similar operation to <a href="https://www.postgresql.org/docs/current/functions-xml.html">xmltable</a> used in SQL databases.
       
   658 			It converts an XML tree structure to the relational form.
       
   659 			In our case, the output is still XML, but in a format that can be read by <code>relpipe-in-xml</code>.
       
   660 			All put together in a single shell script:
       
   661 		</p>
       
   662 		
       
   663 		<m:pre jazyk="bash" src="examples/atom.sh"/>
       
   664 		
       
   665 		<p>Will generate a table with web news:</p>
       
   666 		
       
   667 		<m:pre jazyk="text" src="examples/atom.txt"/>
       
   668 		
       
   669 		<p>
       
   670 			For frequent usage we can create a script or funcrion called <code>relpipe-in-atom</code>
       
   671 			that reads Atom XML on STDIN and generates relational data on STDOUT.
       
   672 			And then do any of these:
       
   673 		</p>
       
   674 		
       
   675 		<m:pre jazyk="bash"><![CDATA[wget … | relpipe-in-atom | relpipe-out-tabular
       
   676 wget … | relpipe-in-atom | relpipe-out-csv
       
   677 wget … | relpipe-in-atom | relpipe-out-gui
       
   678 wget … | relpipe-in-atom | relpipe-out-nullbyte | while read_nullbyte published title url; do echo "$title"; done
       
   679 wget … | relpipe-in-atom | relpipe-out-csv | csv2rec | …
       
   680 ]]></m:pre>
       
   681 
       
   682 		<p>
       
   683 			There are several implementations of XQuery.
       
   684 			<a href="http://galax.sourceforge.net/">Galax</a> is one of them. 
       
   685 			<a href="http://xqilla.sourceforge.net/">XQilla</a> or
       
   686 			<a href="http://basex.org/basex/xquery/">BaseX</a> are another ones (and support newer versions of the standard).
       
   687 			There are also XSLT processors like <a href="http://xmlsoft.org/XSLT/xsltproc2.html">xsltproc</a>.
       
   688 			BaseX can be used instead of Galax – we just replace
       
   689 			<code>galax-run -context-item /dev/stdin</code> with <code>basex -i /dev/stdin</code>.
       
   690 		</p>
       
   691 		
       
   692 		<p>
       
   693 			Reading Atom feeds in a terminal might not be the best way to get news from a website,
       
   694 			but this simple example learns us how to convert arbitrary XML to relational data.
       
   695 			And of course, we can generate multiple relations from a single XML using a single XQuery script.
       
   696 			XQuery can be also used for operations like JOIN or UNION and for filtering and other transformations
       
   697 			as will be shown in further examples.
       
   698 		</p>
       
   699 		
       
   700 		<h2>Read files metadata using relpipe-in-filesystem</h2>
       
   701 		
       
   702 		<p>
       
   703 			Our filesystems contain valuable information and using proper tools we can extract them.
       
   704 			Using <code>relpipe-in-filesystem</code> we can gather metadata of our files and process them in relational way.
       
   705 			This tools does not traverse our filesystem (remember the rule: <em>do one thing and do it well</em>),
       
   706 			instead, it eats a list of file paths separated by <code>\0</code>.
       
   707 			It is typically used together with the <code>find</code> command, but we can also create such list by hand using e.g. <code>printf</code> command or <code>tr \\n \\0</code>.
       
   708 		</p>
       
   709 		
       
   710 		<m:pre jazyk="bash">find /etc/ssh/ -print0 | relpipe-in-filesystem | relpipe-out-tabular</m:pre>
       
   711 		
       
   712 		<p>
       
   713 			In the basic scenario, it behaves like <code>ls -l</code>, just more modular and machine-readable:
       
   714 		</p>
       
   715 		
       
   716 		<pre><![CDATA[filesystem:
       
   717  ╭───────────────────────────────────┬───────────────┬────────────────┬────────────────┬────────────────╮
       
   718  │ path                     (string) │ type (string) │ size (integer) │ owner (string) │ group (string) │
       
   719  ├───────────────────────────────────┼───────────────┼────────────────┼────────────────┼────────────────┤
       
   720  │ /etc/ssh/                         │ d             │              0 │ root           │ root           │
       
   721  │ /etc/ssh/moduli                   │ f             │         553122 │ root           │ root           │
       
   722  │ /etc/ssh/ssh_host_ecdsa_key       │ f             │            227 │ root           │ root           │
       
   723  │ /etc/ssh/sshd_config              │ f             │           3262 │ root           │ root           │
       
   724  │ /etc/ssh/ssh_host_ed25519_key.pub │ f             │             91 │ root           │ root           │
       
   725  │ /etc/ssh/ssh_host_ecdsa_key.pub   │ f             │            171 │ root           │ root           │
       
   726  │ /etc/ssh/ssh_host_rsa_key         │ f             │           1679 │ root           │ root           │
       
   727  │ /etc/ssh/ssh_config               │ f             │           1580 │ root           │ root           │
       
   728  │ /etc/ssh/ssh_host_ed25519_key     │ f             │            399 │ root           │ root           │
       
   729  │ /etc/ssh/ssh_import_id            │ f             │            338 │ root           │ root           │
       
   730  │ /etc/ssh/ssh_host_rsa_key.pub     │ f             │            391 │ root           │ root           │
       
   731  ╰───────────────────────────────────┴───────────────┴────────────────┴────────────────┴────────────────╯
       
   732 Record count: 11]]></pre>
       
   733 
       
   734 		<p>
       
   735 			We can specify desired attributes and also their aliases:
       
   736 		</p>
       
   737 		
       
   738 		<m:pre jazyk="bash"><![CDATA[find /etc/ssh/ -print0 \
       
   739 	| relpipe-in-filesystem \
       
   740 		--file path --as artefact \
       
   741 		--file size \
       
   742 		--file owner --as dear_owner \
       
   743 	| relpipe-out-tabular]]></m:pre>
       
   744 	
       
   745 		<p>And we will get a subset with renamed attributes:</p>
       
   746 	
       
   747 		<pre><![CDATA[filesystem:
       
   748  ╭───────────────────────────────────┬────────────────┬─────────────────────╮
       
   749  │ artefact                 (string) │ size (integer) │ dear_owner (string) │
       
   750  ├───────────────────────────────────┼────────────────┼─────────────────────┤
       
   751  │ /etc/ssh/                         │              0 │ root                │
       
   752  │ /etc/ssh/moduli                   │         553122 │ root                │
       
   753  │ /etc/ssh/ssh_host_ecdsa_key       │            227 │ root                │
       
   754  │ /etc/ssh/sshd_config              │           3262 │ root                │
       
   755  │ /etc/ssh/ssh_host_ed25519_key.pub │             91 │ root                │
       
   756  │ /etc/ssh/ssh_host_ecdsa_key.pub   │            171 │ root                │
       
   757  │ /etc/ssh/ssh_host_rsa_key         │           1679 │ root                │
       
   758  │ /etc/ssh/ssh_config               │           1580 │ root                │
       
   759  │ /etc/ssh/ssh_host_ed25519_key     │            399 │ root                │
       
   760  │ /etc/ssh/ssh_import_id            │            338 │ root                │
       
   761  │ /etc/ssh/ssh_host_rsa_key.pub     │            391 │ root                │
       
   762  ╰───────────────────────────────────┴────────────────┴─────────────────────╯
       
   763 Record count: 11]]></pre>
       
   764 
       
   765 		<p>
       
   766 			We can also choose, which path format fits our needs best:
       
   767 		</p>
       
   768 
       
   769 
       
   770 		<m:pre jazyk="bash"><![CDATA[find ../../etc/ssh/ -print0 \
       
   771 	| relpipe-in-filesystem \
       
   772 		--file path \
       
   773 		--file path_absolute \
       
   774 		--file path_canonical \
       
   775 		--file name \
       
   776 	| relpipe-out-tabular]]></m:pre>
       
   777 	
       
   778 		<p>The <code>path</code> attribute contains the exact same value as was on input. Other formats are derived:</p>
       
   779 	
       
   780 		<pre><![CDATA[filesystem:
       
   781  ╭────────────────────────────────────────┬───────────────────────────────────────────────────┬───────────────────────────────────┬──────────────────────────╮
       
   782  │ path                          (string) │ path_absolute                            (string) │ path_canonical           (string) │ name            (string) │
       
   783  ├────────────────────────────────────────┼───────────────────────────────────────────────────┼───────────────────────────────────┼──────────────────────────┤
       
   784  │ ../../etc/ssh/                         │ /home/hack/../../etc/ssh/                         │ /etc/ssh                          │                          │
       
   785  │ ../../etc/ssh/moduli                   │ /home/hack/../../etc/ssh/moduli                   │ /etc/ssh/moduli                   │ moduli                   │
       
   786  │ ../../etc/ssh/ssh_host_ecdsa_key       │ /home/hack/../../etc/ssh/ssh_host_ecdsa_key       │ /etc/ssh/ssh_host_ecdsa_key       │ ssh_host_ecdsa_key       │
       
   787  │ ../../etc/ssh/sshd_config              │ /home/hack/../../etc/ssh/sshd_config              │ /etc/ssh/sshd_config              │ sshd_config              │
       
   788  │ ../../etc/ssh/ssh_host_ed25519_key.pub │ /home/hack/../../etc/ssh/ssh_host_ed25519_key.pub │ /etc/ssh/ssh_host_ed25519_key.pub │ ssh_host_ed25519_key.pub │
       
   789  │ ../../etc/ssh/ssh_host_ecdsa_key.pub   │ /home/hack/../../etc/ssh/ssh_host_ecdsa_key.pub   │ /etc/ssh/ssh_host_ecdsa_key.pub   │ ssh_host_ecdsa_key.pub   │
       
   790  │ ../../etc/ssh/ssh_host_rsa_key         │ /home/hack/../../etc/ssh/ssh_host_rsa_key         │ /etc/ssh/ssh_host_rsa_key         │ ssh_host_rsa_key         │
       
   791  │ ../../etc/ssh/ssh_config               │ /home/hack/../../etc/ssh/ssh_config               │ /etc/ssh/ssh_config               │ ssh_config               │
       
   792  │ ../../etc/ssh/ssh_host_ed25519_key     │ /home/hack/../../etc/ssh/ssh_host_ed25519_key     │ /etc/ssh/ssh_host_ed25519_key     │ ssh_host_ed25519_key     │
       
   793  │ ../../etc/ssh/ssh_import_id            │ /home/hack/../../etc/ssh/ssh_import_id            │ /etc/ssh/ssh_import_id            │ ssh_import_id            │
       
   794  │ ../../etc/ssh/ssh_host_rsa_key.pub     │ /home/hack/../../etc/ssh/ssh_host_rsa_key.pub     │ /etc/ssh/ssh_host_rsa_key.pub     │ ssh_host_rsa_key.pub     │
       
   795  ╰────────────────────────────────────────┴───────────────────────────────────────────────────┴───────────────────────────────────┴──────────────────────────╯
       
   796 Record count: 11]]></pre>
       
   797 
       
   798 		<p>
       
   799 			We can also <em>select</em> symlink targets or their types.
       
   800 			If some file is missing or is inaccessible due to permissions, only <code>path</code> is printed for it.
       
   801 		</p>
       
   802 		
       
   803 		<p>
       
   804 			Tip: if we are looking for files in the current directory and want omit the „.“ we just call: <code>find -printf '%P\0'</code> instead of <code>find -print0</code>.
       
   805 		</p>
       
   806 		
       
   807 		
       
   808 		<h2>Using relpipe-in-filesystem to read extended attributes</h2>
       
   809 		
       
   810 		<p>
       
   811 			Extended attributes (xattr) are additional <em>key=value</em> pairs that can be attached to our files.
       
   812 			They are not stored inside the files, but on the filesystem.
       
   813 			Thus they are independent of particular file format (which might not support metadata)
       
   814 			and we can use them e.g. for tagging, cataloguing or adding some notes to our files.
       
   815 			Some tools like GNU Wget use extended attributes to store metadata like the original URL from which the file was downloaded.
       
   816 		</p>
       
   817 		
       
   818 		<m:pre jazyk="bash"><![CDATA[wget --recursive --level=1 https://relational-pipes.globalcode.info/
       
   819 find -type f -printf '%P\0' \
       
   820 	| relpipe-in-filesystem --file path --file size --xattr xdg.origin.url  \
       
   821 	| relpipe-out-tabular
       
   822 ]]></m:pre>
       
   823 
       
   824 		<p>And now we know, where the files on our disk came from:</p>
       
   825 
       
   826 		<pre><![CDATA[filesystem:
       
   827  ╭───────────────────────────┬────────────────┬────────────────────────────────────────────────────────────────────╮
       
   828  │ path             (string) │ size (integer) │ xdg.origin.url                                            (string) │
       
   829  ├───────────────────────────┼────────────────┼────────────────────────────────────────────────────────────────────┤
       
   830  │ index.html                │          12159 │ https://relational-pipes.globalcode.info/v_0/                      │
       
   831  │ v_0/atom.xml              │           4613 │ https://relational-pipes.globalcode.info/v_0/atom.xml              │
       
   832  │ v_0/rss.xml               │           4926 │ https://relational-pipes.globalcode.info/v_0/rss.xml               │
       
   833  │ v_0/js/skript.js          │           2126 │ https://relational-pipes.globalcode.info/v_0/js/skript.js          │
       
   834  │ v_0/css/styl.css          │           2988 │ https://relational-pipes.globalcode.info/v_0/css/styl.css          │
       
   835  │ v_0/css/relpipe.css       │           1095 │ https://relational-pipes.globalcode.info/v_0/css/relpipe.css       │
       
   836  │ v_0/css/syntaxe.css       │           3584 │ https://relational-pipes.globalcode.info/v_0/css/syntaxe.css       │
       
   837  │ v_0/index.xhtml           │          12159 │ https://relational-pipes.globalcode.info/v_0/index.xhtml           │
       
   838  │ v_0/grafika/logo.png      │           3298 │ https://relational-pipes.globalcode.info/v_0/grafika/logo.png      │
       
   839  │ v_0/principles.xhtml      │          17171 │ https://relational-pipes.globalcode.info/v_0/principles.xhtml      │
       
   840  │ v_0/roadmap.xhtml         │          11097 │ https://relational-pipes.globalcode.info/v_0/roadmap.xhtml         │
       
   841  │ v_0/faq.xhtml             │          11080 │ https://relational-pipes.globalcode.info/v_0/faq.xhtml             │
       
   842  │ v_0/specification.xhtml   │          12983 │ https://relational-pipes.globalcode.info/v_0/specification.xhtml   │
       
   843  │ v_0/implementation.xhtml  │          10810 │ https://relational-pipes.globalcode.info/v_0/implementation.xhtml  │
       
   844  │ v_0/examples.xhtml        │          76958 │ https://relational-pipes.globalcode.info/v_0/examples.xhtml        │
       
   845  │ v_0/license.xhtml         │          65580 │ https://relational-pipes.globalcode.info/v_0/license.xhtml         │
       
   846  │ v_0/screenshots.xhtml     │           5708 │ https://relational-pipes.globalcode.info/v_0/screenshots.xhtml     │
       
   847  │ v_0/download.xhtml        │           5204 │ https://relational-pipes.globalcode.info/v_0/download.xhtml        │
       
   848  │ v_0/contact.xhtml         │           4940 │ https://relational-pipes.globalcode.info/v_0/contact.xhtml         │
       
   849  │ v_0/classic-example.xhtml │           9539 │ https://relational-pipes.globalcode.info/v_0/classic-example.xhtml │
       
   850  ╰───────────────────────────┴────────────────┴────────────────────────────────────────────────────────────────────╯
       
   851 Record count: 20]]></pre>
       
   852 
       
   853 		<p>
       
   854 			If we like the BeOS/Haiku style, we can create empty files with some attributes attached and use our filesystem as a simple database
       
   855 			and query it using relational tools.
       
   856 			It will lack indexing, but for basic scenarios like <em>address book</em> it will be fast enough
       
   857 			and we can feel a bit of BeOS/Haiku atmosphere in our contemporary GNU/Linux systems.
       
   858 			But be careful with that because some editors delete and recreate files while saving them, which destroys the xattrs.
       
   859 			Tools like <code>rsync</code> or <code>tar</code> with <code>--xattrs</code> option will backup our attributes securely.
       
   860 		</p>
       
   861 
       
   862 		
    29 		
   863 	</text>
    30 	</text>
   864 
    31 
   865 </stránka>
    32 </stránka>