examples: Writing an output filter in Bash v_0
authorFrantišek Kučera <franta-hg@frantovo.cz>
Sun, 16 Dec 2018 13:35:54 +0100
branchv_0
changeset 214 63f31bf2697f
parent 213 cbf25a63a43f
child 215 c7e88edaedc5
examples: Writing an output filter in Bash
relpipe-data/examples.xml
--- a/relpipe-data/examples.xml	Thu Dec 13 14:14:17 2018 +0100
+++ b/relpipe-data/examples.xml	Sun Dec 16 13:35:54 2018 +0100
@@ -89,7 +89,7 @@
 		<h3>relpipe-in-cli: STDIN</h3>
 		
 		<p>
-			The number of CLI arguments is limited and their are passed at once to the process.
+			The number of <abbr title="Command-line interface">CLI</abbr> arguments is limited and they are passed at once to the process.
 			So there is option to pass the values from STDIN instead of CLI arguments.
 			Values on STDIN are expected to be separated by the null-byte.
 			We can generate such data e.g. using <code>echo</code> and <code>tr</code> (or using <code>printf</code> or other commands):
@@ -372,6 +372,58 @@
 			</p>
 		</blockquote>
 		
+		<h2>Writing an output filter in Bash</h2>
+		
+		<p>
+			In previous example we created and output filter in Perl. 
+			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 <em>multi-liner</em> in this case).
+			But we can write such output filter in pure Bash without <code>xargs</code> and <code>perl</code>.
+			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>).
+		</p>
+		
+		<p>
+			We will define a function that will help us with reading the <code>\0</code>-separated values and putting them into shell variables:
+		</p>
+		
+		<m:pre jazyk="bash"><![CDATA[read_nullbyte() { for v in "$@"; do export "$v"; read -r -d '' "$v"; done }]]></m:pre>
+		
+		<!--
+			This version will not require the last \0:
+				read_zero() { for v in "$@"; do export "$v"; read -r -d '' "$v" || [ ! -z "${!v}" ]; done }
+			at least in case when the last value is not missing.
+			Other values might be null/missing: \0\0 is OK.
+		-->
+		
+		<p>
+			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).
+			But it is just a single line function, so not a big deal.
+		</p>
+		
+		<p>
+			And then we just read the values, put them in shell variables and process them in a cycle in a shell block of code:
+		</p>
+		
+		<m:pre jazyk="bash"><![CDATA[relpipe-in-fstab \
+	| relpipe-out-nullbyte \
+	| while read_nullbyte scheme device mount_point fs_type options dump pass; do
+		echo "Device ${scheme:+$scheme=}$device is mounted" \
+		     "at $mount_point and contains $fs_type.";
+	done]]></m:pre>
+	
+		<p>
+			Which will print:
+		</p>
+		
+		<pre><![CDATA[Device UUID=29758270-fd25-4a6c-a7bb-9a18302816af is mounted at / and contains ext4.
+Device /dev/sr0 is mounted at /media/cdrom0 and contains udf,iso9660.
+Device /dev/sde is mounted at /mnt/data and contains ext4.
+Device UUID=a2b5f230-a795-4f6f-a39b-9b57686c86d5 is mounted at /home and contains btrfs.
+Device /dev/mapper/sdf_crypt is mounted at /mnt/private and contains xfs.]]></pre>
+
+		<p>
+			Using this method, we can convert any single relation to any format (preferably text one, but <code>printf</code> can produce also binary data).
+		</p>
+		
 		<h2>Rename VG in /etc/fstab using relpipe-tr-sed</h2>
 		
 		<p>
@@ -508,8 +560,8 @@
 		</p>
 		
 		<p>
-			Then we pass the data to the Bash while cycle.
-			In such simple scenario (just <code>echo</code>), we could use <code>xargs</code> as in examples before,
+			Then we pass the data to the Bash <code>while</code> cycle.
+			In such simple scenario (just <code>echo</code>), we could use <code>xargs</code> as in examples above,
 			but in this syntax, we can write whole block of shell commands for each record/value and do more complex actions with them.
 		</p>