Csa*_*nai 14 command-line bash zsh wildcards
在文件管理器中,您通常可以选择一个文件,然后按住Shift并选择另一个文件。中间的每个文件都将被选择。
我想做bash
/zsh
相当于这个。
即:我想给出 2 个文件名,并在中间包含每个文件名(按字母顺序排列 - 输出它们的方式ls
)。
我知道? {} *
和其他通配符选项,但是我希望能够在名称高度混乱的文件上使用它。
例如:给定文件
$ ls
aoeitoae.txt
oaeistn.txt
oaie.txt
paeoai.txt
sotaoe.txt
Run Code Online (Sandbox Code Playgroud)
我想发出这样的命令rm aoeitoae.txt-oaie.txt
,然后得到:
$ ls
paeoai.txt
sotaoe.txt
Run Code Online (Sandbox Code Playgroud)
我怎样才能实现这个目标?
Gil*_*il' 10
这个答案主要针对 zsh。大部分工作不能在 bash 中轻松完成。
\n许多常见情况都可以使用通配符来完成。尤其:
\nfoo-*
foo[b-m]*
包括foobar
, food
, foomz1
,但不包括fooar
或foon
)IMG-<7-42>.*
包括IMG-8.PNG
和IMG-0042.JPG
但不包括IMG-77.JPG
)使用glob 限定符,有一种简单的方法来识别范围,但它需要计数:foo*([1,3])
匹配 列出的前 3 个文件foo*
,无论它们是什么(如果少于 3 个,则匹配所有文件)。这发生在完成任何排序之后,例如foo*(om[1,3])
匹配名称以foo
.
你可以让 zsh 帮你算出数字。分两步完成:首先将所有匹配项放入数组中,然后使用下标标志 i
查找端点,并且I
(e
如果您想防止任何通配符匹配):是数组中从元素到元素$a[$a[(i)foo],$a[(I)bar]]
的部分,如果或不存在则为空。$a
foo
bar
foo
bar
a=(*.txt(oL))\n# List the files that appear between small.txt and large.txt in a listing by size.\n# Note that files that have the same size as one of the bounds may or may not be included.\necho $a[$a[(I)small.txt],$a[(I)large.txt]]\n
Run Code Online (Sandbox Code Playgroud)\n所以这里的函数完全实现了问题的要求(除了精确的语法,这是无法完成的):
\n# Usage: select_range FROM TO WILDCARD_PATTERN\n# Sets the array $s to the files matching PATTERN from FROM to TO inclusive.\nfunction select_range {\n if (($# < 2)); then\n echo >&2 "select_range: missing range arguments"\n return 120\n fi\n local from=$1 to=$2\n shift 2\n from=$@[(ie)$from]\n if ((from == 0)); then\n echo >&2 "select_range: not matched: $from"\n fi\n to=$@[(Ie)$to]\n if ((to == 0)); then\n echo >&2 "select_range: not matched: $from"\n fi\n s=($@[$from,$to])\n}\n
Run Code Online (Sandbox Code Playgroud)\n用法:select_range aoeitoae.txt oaie.txt * && rm $s
globe
限定符允许您编写任意代码来过滤结果,但它已经开始变得有点笨拙。在复杂的情况下,引用可能会很棘手;为了简单起见,请使用\'
作为分隔符(需要用反斜杠引用)并将过滤器代码放在单引号中,这意味着模式如下所示:foo-*(e\\\'\'code goes here\'\\\')
。(如果引用变得太复杂,请编写一个函数并使用限定符。)按字典顺序+
过滤前后的aoeitoae.txt
文件:。oaie.txt
*(e\\\'\'! [[ $REPLY < aoeitoae.txt || $REPLY > oaie.txt ]]\'\\\')
请注意,过滤器中进行的比较不一定使用与通配符扩展相同的顺序。例如,foo-*(n)
列表foo-9
之前foo-10
得益于限定符n
,但[[ foo-9 > foo-10 ]]
在字符串比较中,并没有类似于对整数子字符串进行数字比较的条件运算符。>
如果要与按数字排序的整数部分进行字符串比较,可以使用n
参数扩展标志进行数组排序,并检查它是否将匹配的名称保留在中间:*(ne\\\'\'a=(b11r $REPLY f10o); [[ $a[2] == "${${(@n)a}[2]}" ]]\'\\\'))
包括b101r
, b11s
, d1
, f02o
, \xe2\x80\xa6,但不包括b9r
, f011
, \xe2\x80\xa6
如果您按日期匹配文件,则可以使用-nt
条件(请注意,文件不比其自身更新):*(ome\\\'\'! [[ $REPLY -ot from || $REPLY -nt to ]]\'\\\')
仅包含在的修改时间和 的修改时间(含)之间修改的文件。from
to
使用 bash 函数:
sfiles ()
(
# run this in a subshell, so we don't have to care if nullglob/dotglob were enabled or not
[ $# -eq 0 ] && exit
local nullsep=0
if [ "$1" = "-0" ]; then
nullsep=1; shift
fi
local first=$1
shift $(($# -1))
local last=$1
local files=( )
shopt -s nullglob dotglob
for i in *; do
# first argument found or array not empty?
if [ "$i" = "$first" ] || [ "${#files[@]}" -ne 0 ]; then
files+=( "$i" )
fi
# last argument found? break loop
[ "$i" = "$last" ] && break
done
if [ "${#files[@]}" -gt 0 ]; then
[ "$nullsep" -eq 1 ] &&
printf '%s\0' "${files[@]}" ||
printf '%s\n' "${files[@]@Q}"
fi
)
Run Code Online (Sandbox Code Playgroud)
它输出第一个参数和最后一个参数(包括)之间的所有文件。
例子:
$ ls -A
btjhyyxrlv.txt otewagahzp.txt .xxx
crlcsbzizl.txt ssffszhdmp.txt 'zdjtgahx q.txt'
hgiagchkgt.txt 'tt'$'\t''aa.txt' 'zmwik zhur.txt'
jusupbivit.txt umikyfucgu.txt 'z otmleqlq.txt'
' kcyigyurc.txt' ' upvpntdfv.txt' .zzz
kfthnpgrxm.txt 'uu'$'\t\t''aa.txt'
lgzsmquxwj.txt wlwexgzohs.txt
Run Code Online (Sandbox Code Playgroud)
$ sfiles c* k*
'crlcsbzizl.txt'
'hgiagchkgt.txt'
'jusupbivit.txt'
' kcyigyurc.txt'
'kfthnpgrxm.txt'
Run Code Online (Sandbox Code Playgroud)
$ sfiles .xxx .zzz
'.xxx'
'zdjtgahx q.txt'
'zmwik zhur.txt'
'z otmleqlq.txt'
'.zzz'
Run Code Online (Sandbox Code Playgroud)
$ LC_ALL=C sfiles .xxx .zzz
'.xxx'
'.zzz'
Run Code Online (Sandbox Code Playgroud)
顺序错误,这个什么也不返回:
$ sfiles .zzz .xxx
Run Code Online (Sandbox Code Playgroud)
使用以下命令删除选定的文件xargs
:
$ sfiles .xxx .zzz | xargs rm
Run Code Online (Sandbox Code Playgroud)
对于带有制表符或换行符的文件名,添加选项-0
作为第一个参数,以进行空分隔输出,无需 bash 引用。
$ sfiles -0 tt* uu* | xargs -0 ls
'tt'$'\t''aa.txt' ' upvpntdfv.txt'
umikyfucgu.txt 'uu'$'\t\t''aa.txt'
Run Code Online (Sandbox Code Playgroud)