lcomma() { sed '
$x;$G;/\(.*\),/!H;//!{$!d
}; $!x;$s//\1/;s/^\n//'
}
To powinno usunąć tylko ostatnie wystąpienie ,
dowolnego pliku wejściowego - i nadal będzie drukować te, w których ,
nie występuje. Zasadniczo buforuje sekwencje linii, które nie zawierają przecinka.
Kiedy napotka przecinek, zamienia bieżący bufor linii z buforem wstrzymania i w ten sposób jednocześnie drukuje wszystkie linie, które wystąpiły od ostatniego przecinka i zwalnia bufor wstrzymania.
Właśnie przeglądałem mój plik historii i znalazłem to:
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
)\"";}
To jest całkiem niezłe. Tak, używa eval
, ale nigdy nie przekazuje mu niczego poza odniesieniem numerycznym do swoich argumentów. Buduje dowolne sed
skrypty do obsługi ostatniego dopasowania. Pokażę ci:
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...'
Wypisuje to na stderr. To jest kopia danych lmatch
wejściowych:
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
Podskładka ed funkcji iteruje wszystkie argumenty jeden raz. Przechodząc nad nimi, odpowiednio iteruje licznik w zależności od kontekstu dla każdego przełącznika i pomija tak wiele argumentów do następnej iteracji. Odtąd robi jedną z kilku rzeczy na argument:
- Dla każdej opcji parser opcja dodaje
$a
się $o
. $a
jest przypisywany na podstawie wartości, $i
która jest zwiększana o liczbę arg dla każdego przetworzonego arg. $a
ma przypisaną jedną z dwóch następujących wartości:
a=$((i+=1))
- jest to przypisywane, jeśli do opcji krótkiej nie dołączono argumentu lub jeśli opcja była długa.
a=$i#-?
- to jest przypisany jeśli opcja jest krótka i nie ma jej arg dołączana do niego.
a=\${$a}${1:+$d\${$(($1))\}}
- Bez względu na początkowe przypisanie, $a
wartość jest zawsze zawijana w nawiasy klamrowe i - w takim -s
przypadku - czasami $i
jest zwiększana o jeszcze jedno i dołączane jest dodatkowo pole rozdzielane.
Powoduje to, że eval
nigdy nie jest przekazywany ciąg zawierający nieznane. Do każdego z argumentów wiersza polecenia odwołuje się ich numeryczny numer argumentu - nawet separator, który jest wyodrębniany z pierwszego znaku pierwszego argumentu i jest jedynym czasem, w którym powinieneś użyć dowolnego znaku, który jest nieskalowany. Zasadniczo funkcja jest generatorem makr - nigdy nie interpretuje wartości argumentów w żaden specjalny sposób, ponieważ sed
może (i oczywiście) z łatwością poradzi sobie z tym podczas analizy skryptu. Zamiast tego rozsądnie układa argumenty w praktyczny skrypt.
Oto niektóre dane wyjściowe debugowania funkcji w pracy:
... 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
'
Dzięki temu lmatch
można łatwo zastosować wyrażenia regularne do danych po ostatnim dopasowaniu w pliku. Wynik polecenia, które uruchomiłem powyżej, to:
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'
... który, biorąc pod uwagę podzbiór danych wejściowych pliku, który następuje po ostatnim /^.0/
dopasowaniu, stosuje następujące podstawienia:
sdd&&&&d
- zastępuje $match
się 4 razy.
sd'dsqd4
- czwarty pojedynczy cytat następujący po początku wiersza od ostatniego meczu.
sd"d\dqd2
- to samo, ale w przypadku podwójnych cytatów i globalnie.
Aby więc pokazać, jak można użyć lmatch
ostatniego przecinka w pliku:
printf "%d, %d %d, %d\n" $(seq 5 5 100) |
lmatch '/\(.*\),' -r\\1
WYNIK:
5, 10 15, 20
25, 30 35, 40
45, 50 55, 60
65, 70 75, 80
85, 90 95 100