如何将 argv 与通配符一起使用?
How do I use argv with a wildcard?
我正在尝试编写一个函数来更改当前目录中所有匹配文件的扩展名:
function chext
if count $args -eq 2 > /dev/null
for f in (ls *$argv[1])
mv (basename $f $argv[2]) (basename $f $argv[1])
end
else
echo "Error: use the following syntax"
echo "chext oldext newext"
end
end
虽然我一直得到这个输出:
(*master) λ chext markdown txt
No matches for wildcard '*$argv[1]'. (Tip: empty matches are allowed in 'set', 'count', 'for'.)
~/.config/fish/config.fish (line 1): ls *$argv[1]
^
in command substitution
called on line 60 of file ~/.config/fish/config.fish
in function 'chext'
called on standard input
with parameter list 'markdown txt'
我知道必须有一种方法可以对变量进行插值并将 *
保留为通配符,但我无法弄清楚。我试过使用 (string join '*' $argv[1])
,但它把通配符变成了字符串。
我确实做到了 几乎 工作:
function chext
if count $args -eq 2 > /dev/null
for f in (ls (string join * $argv[1]))
mv (basename $f $argv[2]) (basename $f $argv[1])
end
else
echo "Error: use the following syntax"
echo "chext oldext newext"
end
end
它删除了我所有文件的扩展名,但没有添加新的,然后给我一个错误,这是所有文件名的组合,并说文件名太长。
更新:
我确定有一种方法可以让 ls
正常工作,但我确实让这个工作成功了:
if count $args -eq 2 > /dev/null
for f in (ls)
mv $f (string replace -r \.$argv[1]$ .$argv[2] (basename $f))
end
else
echo "Error: use the following syntax"
echo "chext oldext newext"
end
end
答案在留言中:
No matches for wildcard '*$argv[1]'. (Tip: empty matches are allowed in 'set', 'count', 'for'.)
这意味着
for i in *argv[1]
有效,
set -l expanded *argv[1]
如果您尝试使用不匹配的 glob 启动任何其他命令,fish 将跳过执行并打印错误。
您的功能还有很多其他问题,请允许我一一解决。
if count $args -eq 2 > /dev/null
count
不接受“-eq 2”参数。只要给它一个参数,它就会 return 0(即 true),所以这将永远是 true。
您尝试做的是 if test (count $args) -eq 2
。
同样有效的(也是我碰巧更喜欢的)是 if set -q argv[2]
(另外,它是 "argv",而不是 "args")。
for f in (ls *$argv[1])
请不要使用ls
的输出。它在 fish 中的问题没有在 bash 中那么多(一旦文件名称中包含 space、制表符或换行符,它就会中断),但这是不必要的(它启动一个额外的过程)并且仍然有一个问题 - 当文件名称中有换行符时它会中断。
做for f in *$argv[1]
也能很好的解决你的问题
mv (basename $f $argv[2]) (basename $f $argv[1])
我不确定您在这里使用的 basename
是什么,但我的只是 删除了 一个后缀。因此,如果您执行 chext .opus .ogg
,这将执行
mv (basename song.opus .ogg) (basename song.opus .opus)
这将解析为
mv song.opus song
就个人而言,我会为此使用 string replace
。像
mv $f (string replace -- $argv[1] $argv[2] $f)
(注意:如果扩展字符串出现在前面,这会做错事,例如,如果你有一个名为 "f.ogg-banana.ogg" 的文件,只有第一个“.ogg”会被改变。你可能想使用常规表达式:string replace -r -- "$argv[1]$" $argv[2] $f
)
我正在尝试编写一个函数来更改当前目录中所有匹配文件的扩展名:
function chext
if count $args -eq 2 > /dev/null
for f in (ls *$argv[1])
mv (basename $f $argv[2]) (basename $f $argv[1])
end
else
echo "Error: use the following syntax"
echo "chext oldext newext"
end
end
虽然我一直得到这个输出:
(*master) λ chext markdown txt
No matches for wildcard '*$argv[1]'. (Tip: empty matches are allowed in 'set', 'count', 'for'.)
~/.config/fish/config.fish (line 1): ls *$argv[1]
^
in command substitution
called on line 60 of file ~/.config/fish/config.fish
in function 'chext'
called on standard input
with parameter list 'markdown txt'
我知道必须有一种方法可以对变量进行插值并将 *
保留为通配符,但我无法弄清楚。我试过使用 (string join '*' $argv[1])
,但它把通配符变成了字符串。
我确实做到了 几乎 工作:
function chext
if count $args -eq 2 > /dev/null
for f in (ls (string join * $argv[1]))
mv (basename $f $argv[2]) (basename $f $argv[1])
end
else
echo "Error: use the following syntax"
echo "chext oldext newext"
end
end
它删除了我所有文件的扩展名,但没有添加新的,然后给我一个错误,这是所有文件名的组合,并说文件名太长。
更新:
我确定有一种方法可以让 ls
正常工作,但我确实让这个工作成功了:
if count $args -eq 2 > /dev/null
for f in (ls)
mv $f (string replace -r \.$argv[1]$ .$argv[2] (basename $f))
end
else
echo "Error: use the following syntax"
echo "chext oldext newext"
end
end
答案在留言中:
No matches for wildcard '*$argv[1]'. (Tip: empty matches are allowed in 'set', 'count', 'for'.)
这意味着
for i in *argv[1]
有效,
set -l expanded *argv[1]
如果您尝试使用不匹配的 glob 启动任何其他命令,fish 将跳过执行并打印错误。
您的功能还有很多其他问题,请允许我一一解决。
if count $args -eq 2 > /dev/null
count
不接受“-eq 2”参数。只要给它一个参数,它就会 return 0(即 true),所以这将永远是 true。
您尝试做的是 if test (count $args) -eq 2
。
同样有效的(也是我碰巧更喜欢的)是 if set -q argv[2]
(另外,它是 "argv",而不是 "args")。
for f in (ls *$argv[1])
请不要使用ls
的输出。它在 fish 中的问题没有在 bash 中那么多(一旦文件名称中包含 space、制表符或换行符,它就会中断),但这是不必要的(它启动一个额外的过程)并且仍然有一个问题 - 当文件名称中有换行符时它会中断。
做for f in *$argv[1]
也能很好的解决你的问题
mv (basename $f $argv[2]) (basename $f $argv[1])
我不确定您在这里使用的 basename
是什么,但我的只是 删除了 一个后缀。因此,如果您执行 chext .opus .ogg
,这将执行
mv (basename song.opus .ogg) (basename song.opus .opus)
这将解析为
mv song.opus song
就个人而言,我会为此使用 string replace
。像
mv $f (string replace -- $argv[1] $argv[2] $f)
(注意:如果扩展字符串出现在前面,这会做错事,例如,如果你有一个名为 "f.ogg-banana.ogg" 的文件,只有第一个“.ogg”会被改变。你可能想使用常规表达式:string replace -r -- "$argv[1]$" $argv[2] $f
)