lcomma() { sed '
$x;$G;/\(.*\),/!H;//!{$!d
}; $!x;$s//\1/;s/^\n//'
}
Itu harus menghapus hanya kejadian terakhir ,
dalam file input apa pun - dan itu masih akan mencetak yang ,
tidak terjadi. Pada dasarnya, ini mendukung urutan garis yang tidak mengandung koma.
Ketika bertemu koma, ia menukar buffer garis saat ini dengan buffer terus dan dengan cara itu secara bersamaan mencetak semua baris yang terjadi sejak koma terakhir dan membebaskan buffer penahannya.
Saya baru saja menggali file sejarah saya dan menemukan ini:
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
)\"";}
Sebenarnya cukup bagus. Ya, itu digunakan eval
, tetapi tidak pernah melewati apa pun di luar referensi numerik ke argumennya. Itu membangun sed
skrip sewenang-wenang untuk menangani pertandingan terakhir. Saya akan menunjukkan kepada Anda:
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...'
Yang mencetak berikut ini ke stderr. Ini adalah salinan lmatch
input:
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
Subshell fungsi ed iterates melalui semua argumennya sekali. Ketika ia berjalan di atasnya mereka itu counter yang tepat tergantung pada konteks untuk setiap switch dan melompati banyak argumen untuk iterasi berikutnya. Sejak saat itu ia melakukan satu dari beberapa hal per argumen:
- Untuk setiap opsi pilihan parser menambahkan
$a
ke $o
. $a
ditugaskan berdasarkan nilai $i
yang bertambah dengan jumlah arg untuk setiap arg yang diproses. $a
ditugaskan salah satu dari dua nilai berikut:
a=$((i+=1))
- ini diberikan jika salah satu opsi pendek tidak memiliki argumennya ditambahkan atau jika opsi itu panjang.
a=$i#-?
- ini ditugaskan jika opsi adalah pendek dan tidak memiliki arg yang ditambahkan untuk itu.
a=\${$a}${1:+$d\${$(($1))\}}
- Terlepas dari penugasan awal, $a
nilai selalu dibungkus dalam kurung dan - dalam -s
kasus - kadang-kadang $i
bertambah satu lagi dan bidang tambahan dibatasi ditambahkan.
Hasilnya adalah bahwa eval
tidak pernah melewati string yang mengandung sesuatu yang tidak diketahui. Setiap argumen baris perintah dirujuk dengan nomor argumen numeriknya - bahkan pembatas yang diekstraksi dari karakter pertama argumen pertama dan merupakan satu-satunya waktu Anda harus menggunakan karakter apa pun yang tidak terhindar. Pada dasarnya, fungsinya adalah generator makro - ia tidak pernah menginterpretasikan nilai argumen dengan cara khusus karena sed
dapat (dan akan, tentu saja) dengan mudah mengatasinya ketika mem-parsing skrip. Alih-alih, itu hanya dengan bijaksana mengatur argumennya menjadi naskah yang bisa diterapkan.
Berikut ini beberapa hasil debug fungsi di tempat kerja:
... 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
'
Dan lmatch
dapat digunakan untuk dengan mudah menerapkan regex ke data setelah pertandingan terakhir dalam sebuah file. Hasil dari perintah yang saya jalankan di atas adalah:
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'
... yang, mengingat subset dari input file yang mengikuti terakhir kali /^.0/
dicocokkan, menerapkan substitusi berikut:
sdd&&&&d
- Mengganti $match
sendiri 4 kali.
sd'dsqd4
- kutipan tunggal keempat mengikuti awal baris sejak pertandingan terakhir.
sd"d\dqd2
- Dita, tetapi untuk tanda kutip ganda dan global.
Jadi, untuk mendemonstrasikan bagaimana seseorang dapat menggunakan lmatch
untuk menghapus koma terakhir dalam file:
printf "%d, %d %d, %d\n" $(seq 5 5 100) |
lmatch '/\(.*\),' -r\\1
KELUARAN:
5, 10 15, 20
25, 30 35, 40
45, 50 55, 60
65, 70 75, 80
85, 90 95 100