Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
commands:builtin:mapfile [2012/03/08 08:47]
ormaaj [The callback] read + mapfile combination.
commands:builtin:mapfile [2019/12/05 16:59] (current)
willdye Fixed a minor syntax error (excess right-paren)
Line 1: Line 1:
 ====== The mapfile builtin command ====== ====== The mapfile builtin command ======
-:V4: 
  
 ===== Synopsis ===== ===== Synopsis =====
Line 44: Line 43:
 A very simple example might be to use it as a kind of progress bar. This will print a dot for each line read. Note the escaped comment to hide the appended words from printf. A very simple example might be to use it as a kind of progress bar. This will print a dot for each line read. Note the escaped comment to hide the appended words from printf.
  
-<​code>​$ printf '​%s\n'​ {1..5} | mapfile -c 1 -C '​printf . \#' ​)+<​code>​$ printf '​%s\n'​ {1..5} | mapfile -c 1 -C '​printf . \#'
 .....</​code>​ .....</​code>​
  
Line 89: Line 88:
 </​code>​ </​code>​
  
-This example based upon yet another #bash question illustrates mapfile in combination with read. The sample input is the heredoc to ''​main''​. The goal is to build a "​struct"​ based upon records in the input file made up from the numbers following the colon on each line. Every 3rd line is a key followed by 2 corresponding fields. The showRecord function takes a key and returns the record. +This example based on yet another #bash question illustrates mapfile in combination with read. The sample input is the heredoc to ''​main''​. The goal is to build a "​struct"​ based upon records in the input file made up of the numbers following the colon on each line. Every 3rd line is a key followed by 2 corresponding fields. The showRecord function takes a key and returns the record. 
-<​code>#​!/​usr/​bin/​env bash+ 
 +<​code>​ 
 +#​!/​usr/​bin/​env bash
  
 showRecord() { showRecord() {
Line 97: Line 98:
  
 parseRecords() { parseRecords() {
 +    trap 'unset -f _f' RETURN
     _f() {     _f() {
         local x         local x
         IFS=: read -r _ x         IFS=: read -r _ x
-        keys[x]=n+++        ​((keys[x]=n++))
     }     }
- +    ​local n
-    trap 'unset -f _f' RETURN +
-    ​local -i n+
  
     _f     _f
-    mapfile -tc2 -C _f vals +    mapfile -tc2 -C _f "​$1"​ 
-    ​vals=("${vals[@]##​*:​}"​)+    ​eval "​$1"'​=("${'"​$1"'​[@]##​*:​}"​)' # Return the array with some modification
 } }
  
 main() { main() {
-    local -ai keys +    local -keys vals 
-    parseRecords+    parseRecords ​vals
     showRecord "​$1"​     showRecord "​$1"​
 } }
  
-main "$@" <<​-"​EOF"​+main "$1" <<​-"​EOF"​
 fabric.domain:​123 fabric.domain:​123
 routex:1 routex:1
Line 124: Line 124:
 routex:6 routex:6
 routey:4 routey:4
-EOF</​code>​+EOF 
 +</​code>​
  
-For example, running ​"scriptname 321" ​would output ​"key[321] = 6, 4". Every 2 lines mapfile ​reads, the function _f is called which reads one line. Since the first line in the file is a key, and _f is responsible for the keys, it gets called ​once before mapfile ​so that mapfile starts reading the second line of input, calling _f with each subsequent 2 iterations. The RETURN trap is nothing to worry about, its just how I implement "​private methods"​ in Bash.+For example, running ​''​scriptname 321'' ​would output ​''​key[321] = 6, 4''​. Every 2 lines read by ''​mapfile''​, the function ​''​_f'' ​is calledwhich reads one additional ​line. Since the first line in the file is a key, and ''​_f'' ​is responsible for the keys, it gets called ​first so that ''​mapfile'' ​starts ​by reading the second line of input, calling ​''​_f'' ​with each subsequent 2 iterations. The RETURN trap is unimportant.
 ===== Bugs ===== ===== Bugs =====
  
-  * Early implementations were buggy. For example, ''​mapfile''​ filling the readline history buffer with calls to the ''​CALLBACK''​. This was fixed in 4.1 beta. Some bugs may still exist+  * Early implementations were buggy. For example, ''​mapfile''​ filling the readline history buffer with calls to the ''​CALLBACK''​. This was fixed in 4.1 beta. 
 +  * ''​mapfile -n''​ reads an extra line beyond the last line assigned to the array, through Bash. [[ftp://​ftp.gnu.org/​gnu/​bash/​bash-4.2-patches/​bash42-035 | Fixed in 4.2.35]]
 +  * ''​mapfile''​ callbacks could cause a crash if the variable being assigned is manipulated in certain ways. [[https://​lists.gnu.org/​archive/​html/​bug-bash/​2013-01/​msg00039.html]]. Fixed in 4.3.
 ===== To Do ===== ===== To Do =====
   * Create an implementation as a shell function that's portable between Ksh, Zsh, and Bash (and possibly other bourne-like shells with array support).   * Create an implementation as a shell function that's portable between Ksh, Zsh, and Bash (and possibly other bourne-like shells with array support).