lcomma() { sed '
$x;$G;/\(.*\),/!H;//!{$!d
}; $!x;$s//\1/;s/^\n//'
}
Це повинно видалити лише останнє виникнення ,у будь-якому вхідному файлі - і воно все одно буде друкувати ті, у яких а ,не відбувається. В основному, він буферизує послідовності рядків, які не містять коми.
Коли він стикається з комою, він заміняє буфер поточного рядка буфером утримування і таким чином одночасно друкує всі рядки, що виникли з моменту останньої коми, і звільняє її буфер утримування.
Я щойно переглядав мій файл історії і виявив це:
lmatch(){ set "USAGE:\
lmatch /BRE [-(((s|-sub) BRE)|(r|-ref)) REPL [-(f|-flag) FLAG]*]*
" "${1%"${1#?}"}" "$@"
eval "${ZSH_VERSION:+emulate sh}"; eval '
sed " 1x; \\$3$2!{1!H;\$!d
}; \\$3$2{x;1!p;\$!d;x
}; \\$3$2!x;\\$3$2!b'"
$( unset h;i=3 p=:-:shfr e='\033[' m=$(($#+1)) f=OPTERR
[ -t 2 ] && f=$e\2K$e'1;41;17m}\r${h-'$f$e\0m
f='\${$m?"\"${h-'$f':\t\${$i$e\n}\$1\""}\\c' e=} _o=
o(){ IFS=\ ;getopts $p a "$1" &&
[ -n "${a#[?:]}" ] &&
o=${a#-}${OPTARG-${1#-?}} ||
! eval "o=$f;o=\${o%%*\{$m\}*}"
}; a(){ case ${a#[!-]}$o in (?|-*) a=;;esac; o=
set $* "${3-$2$}{$((i+=!${#a}))${a:+#-?}}"\
${3+$2 "{$((i+=1))$e"} $2
IFS=$; _o=${_o%"${3+$_o} "*}$*\
}; while eval "o \"\${$((i+=(OPTIND=1)))}\""
do case ${o#[!$a]} in
(s*|ub) a s 2 '' ;;
(r*|ef) a s 2 ;;
(f*|lag) a ;;
(h*|elp) h= o; break ;;
esac; done; set -f; printf "\t%b\n\t" $o $_o
)\"";}
Насправді це дуже добре. Так, він використовує eval, але він ніколи нічого не передає йому, крім числового посилання на його аргументи. Він будує довільні sedсценарії для обробки останнього збігу. Я покажу тобі:
printf "%d\" %d' %d\" %d'\n" $(seq 5 5 200) |
tee /dev/fd/2 |
lmatch d^.0 \ #all re's delimit w/ d now
-r '&&&&' \ #-r or --ref like: '...s//$ref/...'
--sub \' sq \ #-s or --sub like: '...s/$arg1/$arg2/...'
--flag 4 \ #-f or --flag appended to last -r or -s
-s\" \\dq \ #short opts can be '-s $arg1 $arg2' or '-r$arg1'
-fg #tacked on so: '...s/"/dq/g...'
Це друкує наступне на stderr. Це копія lmatchвхідного запису:
5" 10' 15" 20'
25" 30' 35" 40'
45" 50' 55" 60'
65" 70' 75" 80'
85" 90' 95" 100'
105" 110' 115" 120'
125" 130' 135" 140'
145" 150' 155" 160'
165" 170' 175" 180'
185" 190' 195" 200'
evalПідзаголовок функції Ed повторно повторюється через всі її аргументи. Під час проходу над ними він ітерує лічильник відповідним чином залежно від контексту кожного перемикача і пропускає через це багато аргументів для наступної ітерації. З цього моменту він робить одну з кількох речей за аргументом:
- Для кожного варіанта параметр парсер додає
$aдо $o. $aпризначається на основі значення, $iяке збільшується на кількість аргументів для кожного обробленого аргументу. $aприсвоюється одне з двох наступних значень:
a=$((i+=1)) - це призначається, якщо до короткого варіанту не доданий до нього аргумент або якщо варіант був довгим.
a=$i#-?- це призначається , якщо опція є коротким і зовсім є її аргумент додається до нього.
a=\${$a}${1:+$d\${$(($1))\}}- Незалежно від початкового призначення, $aзначення завжди загортається в дужки і - у -sвипадку - іноді $iзбільшується ще одне і додатково розмежоване поле додається.
Результатом є те, що evalніколи не передається рядок, що містить невідомі. Кожен з аргументів командного рядка посилається на їх числовий номер аргументу - навіть роздільник, який витягується з першого символу першого аргументу, і це єдиний раз, коли ви повинні використовувати будь-який символ, який не змінюється. В основному, функція є генератором макрокоманд - вона ніколи не інтерпретує значення аргументів особливим чином, оскільки sedможе (і, звичайно,) легко впорається з цим, коли аналізує сценарій. Натомість він просто розумно впорядковує свої аргументи під справний сценарій.
Ось деякі результати налагодження функції на роботі:
... sed " 1x;\\$2$1!{1!H;\$!d
}; \\$2$1{x;1!p;\$!d;x
}; \\$2$1!x;\\$2$1!b
s$1$1${4}$1
s$1${6}$1${7}$1${9}
s$1${10#-?}$1${11}$1${12#-?}
"
++ sed ' 1x;\d^.0d!{1!H;$!d
}; \d^.0d{x;1!p;$!d;x
}; \d^.0d!x;\d^.0d!b
sdd&&&&d
sd'\''dsqd4
sd"d\dqdg
'
І тому lmatchможна легко застосовувати регулярні вирази до даних після останнього збігу у файлі. Результат команди, яку я пробіг вище:
5" 10' 15" 20'
25" 30' 35" 40'
45" 50' 55" 60'
65" 70' 75" 80'
85" 90' 95" 100'
101010105dq 110' 115dq 120'
125dq 130' 135dq 140sq
145dq 150' 155dq 160'
165dq 170' 175dq 180'
185dq 190' 195dq 200'
... який, з огляду на підмножину вхідного файлу, що відповідає останньому разом /^.0/, застосовує такі підстановки:
sdd&&&&d- замінює $matchсебе 4 рази.
sd'dsqd4 - четверта одноцітна пропозиція після початку рядка з моменту останнього матчу.
sd"d\dqd2 - ditto, але для подвійних лапок та глобально.
Отже, щоб продемонструвати, як можна використовувати lmatchдля видалення останньої коми з файлу:
printf "%d, %d %d, %d\n" $(seq 5 5 100) |
lmatch '/\(.*\),' -r\\1
ВИХІД:
5, 10 15, 20
25, 30 35, 40
45, 50 55, 60
65, 70 75, 80
85, 90 95 100