如何将argv与通配符一起使用?

时间:2017-03-11 19:52:43

标签: fish

我试图编写一个函数来改变当前目录中所有匹配文件的扩展名:

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

1 个答案:

答案 0 :(得分:3)

答案在信息中:

  

没有匹配的通配符'* $ argv [1]'。 (提示:'strong','count','for'允许空匹配。)

这意味着

for i in *argv[1]

一样有用
set -l expanded *argv[1]

如果您尝试使用与任何内容都不匹配的glob启动任何其他命令,fish将跳过执行并打印错误。

您的功能还有许多其他问题,请允许我逐一浏览。

  

如果计数$ args -eq 2>的/ dev / null的

count不接受“-eq 2”参数。

,只要给出一个参数,它就会返回0(即为真)

您尝试做的是if test (count $args) -eq 2

什么也有效(以及我喜欢的更多)是if set -q argv[2]

(另外,它是“arg v ”,而不是“args”)。

  

表示f in(ls * $ argv [1])

请不要使用ls的输出。它在鱼类中没有像在bash中那样多的问题(一旦文件在名称中有空格,制表符或换行符就会中断),但这是不必要的(它启动了一个额外的过程)并且仍然有问题 - 当文件名称中有换行符时它会中断。

只需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