lcomma() { sed '
$x;$G;/\(.*\),/!H;//!{$!d
}; $!x;$s//\1/;s/^\n//'
}
Điều đó sẽ chỉ loại bỏ sự xuất hiện cuối cùng của một ,
trong bất kỳ tệp đầu vào nào - và nó vẫn sẽ in những lần ,
không xảy ra. Về cơ bản, nó đệm các chuỗi các dòng không chứa dấu phẩy.
Khi gặp dấu phẩy, nó hoán đổi bộ đệm dòng hiện tại bằng bộ đệm giữ và theo cách đó đồng thời in ra tất cả các dòng xảy ra kể từ dấu phẩy cuối cùng và giải phóng bộ đệm giữ của nó.
Tôi chỉ đào qua tập tin lịch sử của mình và tìm thấy điều này:
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
)\"";}
Nó thực sự khá tốt. Vâng, nó sử dụng eval
, nhưng nó không bao giờ chuyển bất cứ thứ gì cho nó ngoài một tham chiếu số cho các đối số của nó. Nó xây dựng các sed
kịch bản tùy ý để xử lý một trận đấu cuối cùng. Tôi sẽ cho bạn thấy:
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...'
Mà in sau đây để stderr. Đây là bản sao lmatch
đầu vào của:
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'
Hàm con eval
ed của hàm lặp lại thông qua tất cả các đối số của nó một lần. Khi nó đi qua chúng, nó lặp lại một bộ đếm một cách thích hợp tùy thuộc vào ngữ cảnh cho mỗi công tắc và bỏ qua nhiều đối số cho lần lặp tiếp theo. Từ đó trở đi, một trong một vài điều cho mỗi đối số:
- Đối với mỗi tùy chọn, trình phân tích cú pháp tùy chọn thêm
$a
vào $o
. $a
được chỉ định dựa trên giá trị $i
được tăng theo số lượng arg cho mỗi arg được xử lý. $a
được gán một trong hai giá trị sau:
a=$((i+=1))
- điều này được chỉ định nếu một tùy chọn ngắn không có đối số của nó được nối với nó hoặc nếu tùy chọn đó là một đối số dài.
a=$i#-?
- điều này được gán nếu tùy chọn là một trong ngắn hạn và không có arg của nó nối vào nó.
a=\${$a}${1:+$d\${$(($1))\}}
- Bất kể chỉ định ban đầu, $a
giá trị của luôn được gói trong dấu ngoặc nhọn và - trong -s
trường hợp - đôi khi $i
được tăng thêm một trường nữa và trường được phân cách bổ sung được thêm vào.
Kết quả là eval
không bao giờ được thông qua một chuỗi có chứa bất kỳ ẩn số nào. Mỗi đối số dòng lệnh được gọi bằng số đối số số của chúng - ngay cả dấu phân cách được trích xuất từ ký tự đầu tiên của đối số đầu tiên và là lần duy nhất bạn nên sử dụng bất kỳ ký tự nào không được bỏ qua. Về cơ bản, hàm là một trình tạo macro - nó không bao giờ diễn giải các giá trị của các đối số theo bất kỳ cách đặc biệt nào vì dĩ nhiên,sed
có thể (và sẽ) dễ dàng xử lý điều đó khi phân tích cú pháp kịch bản. Thay vào đó, nó chỉ hợp lý sắp xếp các đối số của nó thành một kịch bản khả thi.
Đây là một số đầu ra gỡ lỗi của chức năng tại nơi làm việc:
... 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
'
Và do đó, lmatch
có thể được sử dụng để dễ dàng áp dụng regexes cho dữ liệu sau lần khớp cuối cùng trong một tệp. Kết quả của lệnh tôi chạy ở trên là:
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'
... trong đó, với tập hợp con của đầu vào tệp theo sau lần cuối /^.0/
được khớp, áp dụng các thay thế sau:
sdd&&&&d
- thay thế $match
bằng chính nó 4 lần.
sd'dsqd4
- trích dẫn đơn thứ tư sau đầu dòng kể từ trận đấu cuối cùng.
sd"d\dqd2
- ditto, nhưng cho dấu ngoặc kép và toàn cầu.
Và vì vậy, để chứng minh cách người ta có thể sử dụng lmatch
để xóa dấu phẩy cuối cùng trong tệp:
printf "%d, %d %d, %d\n" $(seq 5 5 100) |
lmatch '/\(.*\),' -r\\1
ĐẦU RA:
5, 10 15, 20
25, 30 35, 40
45, 50 55, 60
65, 70 75, 80
85, 90 95 100