Issue
My script loads a "categories" array with chosen terminal commands. This array is then used to yank matching ".bash_history" records into separate category files. My function: "extract_records()" extracts each category using an ERE grep:
BASH_HISTORY="$HOME"/.bash_history
...
# (where "$1" here is a category)
grep -E "^($1 )" "$BASH_HISTORY" >> ".bash_history.$1"
Once the chosen records are grepped from "$BASH_HISTORY" into individual category files, they are then removed from "$BASH_HISTORY". This is done using "grep -v -e" patterns where the category list is re-specified.
My script works but a potential problem exists: the list of history command keywords is defined twice, once in the array and then in a grep pattern list. Excerpted from the script:
#!/usr/bin/bash--------------------------------------------------
# original array definition.
categories=(apt cat dpkg echo file find git grep less locate)
...
for i in "${categories[@]}"; do
extract_records "$i" # which does the grep -E shown above.
done
...
# now remove what has been categorized to separate files.
grep -E -v \
-e "^(apt )" \
-e "^(cat )" \
-e "^(dpkg )" \
... \
"$BASH_HISTORY" >> "$BASH_HISTORY".$$
# finally the temporary "$$" file is optionally sorted and moved
# back as the main "$BASH_HISTORY".
The first part calls extract_records() each time to grep and create each category file. The second part uses a single grep to remove records using a pattern list, re-specified based on the array. PROBLEM: Potentially, the two independent lists can be mismatched.
Optimally, the array: "${categories[@]}" should be used for each part: extracting chosen records, and then rebuilding "$BASH_HISTORY" without the separated records. This would replace my now using the "grep -E -v" pattern list. Something of the sort:
grep -E -v "^(${categories[@]})" "$BASH_HISTORY"
It's nice and compact, but this does not work.
The goal is to divide out oft used terminal commands into separate files so as to keep "$BASH_HISTORY" reasonably small. The separately saved records can then be recalled using another script that functions like the Bash's internal history facility. In this way, no history is lost and everything is grouped and better managed.
Solution
Something of the sort:
grep -E -v "^(${categories[@]})" "$BASH_HISTORY"
This is close to working, only the separating spaces are to be replaced by the regular expression alternative token |
. The Bash Reference Manual gives a useful hint:
If the word is double-quoted,
${name[*]}
expands to a single word with the value of each array member separated by the first character of theIFS
variable…
So, IFS=\|; grep -E -v "^(${categories[*]}) " "$BASH_HISTORY"
works as desired.
(Note that I added the space after the words in the pattern.)
Answered By - Armali Answer Checked By - Timothy Miller (WPSolving Admin)