Is there a UNIX mechanism for replacing matched strings dynamically--with a function of the matched string?
E.g., say I want to replace URL matches with their URL-encoded counterparts or a convert certain matches from snake_case to camelCase, or just upper-case them?
Ruby has gsub method that takes a lambda ("a block" in ruby parlance), but I'd rather not use ruby.
I tried with standard tools and FIFO, but I keep losing white space around my matches somewhere in the read part (see below). Any guesses?
#!/bin/bash
d="\f" #<=A character that's not expected in the input
swapNewlines() { tr "$d"'\n' '\n'"$d"; } #Since unix tools are line-oriented
#Sample transformation -- coloring red
export C_red="$(tput setaf 1)"
export C_normal="$(tput sgr0)"
transform(){ printf "$C_red%s\n$C_normal" "$*"; }
even() { sed -n '2~2p'; }
odd() { sed -n '1~2p'; }
#Open an anonymous FIFO and assign that FD to variable whose names comes on $1
mkchan(){
local __name="${1:-FD}" __tmpd= __ret=1
if __tmpd="`mktemp -d`" && mkfifo "$__tmpd/p" && eval "exec {"$__name"}<>"'$__tmpd/p'; then
__ret=0
fi
rm -rf "$__tmpd"
return "$__ret"
}
#No-op
df |sed 's/\<[1]*\>/'"$d"'\0'"$d"'/g' | swapNewlines | swapNewlines |tr -d "$d"
printf '%s\n' -------------------------------------------------------
mkchan fd; export fd
#Surround matches with the "$d" character and swap newlines with fd; then do line-processing
df |sed 's/\<[1]*\>/'"$d"'\0'"$d"'/g' | swapNewlines |
tee >(even >&"$fd") |
odd | while read o;
do printf "%s\n" "$o"
read e <&"$fd"
#printf '%s\n' "$e"
transform "$e"
done |
swapNewlines |tr -d "$d"
while IFS= read -r o... doIFS= read -r o... but a better approach is to setIFSin the script so you don't have to loop over the assignment. it is better still not to useread, but to coagulate the data in more capable reader utility and.dot what you want (as.will typically pull data in 4k blocks rather than byte by byte). - and this is problematic:eval "exec {"$__name"}<>"'$__tmpd/p'– mikeserv Jan 01 '16 at 17:42s///can be an arbitrary expression when theeflag is used. E.g. to uppercase:perl -pe 's/(pattern)/ uc $1 /ge' file– glenn jackman Jan 01 '16 at 22:04