2017-03-11 1 views
0

Je suis en train d'écrire une fonction qui va changer l'extension pour tous les fichiers correspondant dans le répertoire courant:Comment utiliser argv avec un caractère générique?

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 

Je continue à obtenir cette sortie si:

(*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' 

Je sais qu'il doit y avoir un moyen d'interpoler la variable et de garder * en tant que caractère générique, mais je ne peux pas le comprendre. J'ai essayé d'utiliser (string join '*' $argv[1]), mais il a transformé le caractère générique en une chaîne.

J'ai eu ce à presque travail:

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 

Il a supprimé les extensions de tous mes fichiers, mais ne pas ajouter le nouveau, puis m'a donné une erreur qui était du fichier les noms sont combinés et le nom de fichier est trop long.

MISE À JOUR:

Je suis sûr qu'il ya un moyen d'obtenir le travail ls correct, mais je n'obtenir ce travail avec succès:

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 

Répondre

2

La réponse est dans le message:

Aucune correspondance pour le caractère générique '* $ argv [1]'. (Astuce: matchs vides sont autorisés dans 'set', 'count', 'pour'.)

Cela signifie

for i in *argv[1] 

œuvres, tout comme

set -l expanded *argv[1] 

Si vous essayez de lancer toute autre commande avec un glob qui ne correspond à rien, le poisson sautera l'exécution et imprime une erreur.


Votre fonction comporte un certain nombre d'autres problèmes, permettez-moi de les parcourir un par un.

si le nombre $ args -eq 2>/dev/null

count ne prend pas l'argument "-eq 2". Il renverra 0 (c'est-à-dire vrai) chaque fois qu'il aura un argument, donc ce sera toujours vrai.

Ce que vous avez essayé de faire était if test (count $args) -eq 2.

Ce qui fonctionne aussi (et ce que je suis comme plus) est if set -q argv[2]

(également, il est "arg v", pas "args").

pour f (dans ls * $ argv [1])

S'il vous plaît ne pas utiliser la sortie de ls. Il n'a pas autant de problèmes dans le poisson que dans bash (où il va se casser quand un fichier a un espace, une tabulation ou une nouvelle ligne dans le nom), mais c'est inutile (il lance un processus supplémentaire) et a toujours un problème - il va casser quand un fichier a un retour à la ligne dans son nom.

Juste faire for f in *$argv[1], ce qui va aussi bien résoudre votre question.

mv (basename $f $argv[2]) (basename $f $argv[1]) 

Je ne suis pas sûr de ce que basename vous utilisez ici, mais le mien juste supprime un suffixe. Donc, si vous avez fait chext .opus .ogg, ce exécuterait

mv (basename song.opus .ogg) (basename song.opus .opus) 

qui résoudrait à

mv song.opus song 

Personnellement, j'utiliser string replace pour cela. Quelque chose comme

mv $f (string replace -- $argv[1] $argv[2] $f) 

(Note: Ceci ferait la mauvaise chose si la chaîne d'extension apparaît avant, par exemple, si vous aviez un fichier appelé « f.ogg-banana.ogg » seul le premier « .ogg » serait Vous voudrez peut-être utiliser des expressions régulières pour cela: string replace -r -- "$argv[1]\$" $argv[2] $f)

+0

Wow, merci beaucoup de passer le temps de passer par ces problèmes! J'ai trouvé les portions 'ls' et' basename' dans un autre post SO et essayé de les utiliser, mais comme vous pouvez le voir, cela n'a pas fonctionné. Je suis content de voir que la solution que j'avais ajoutée à ma question, qui utilise le remplacement de chaîne, était la bonne. Merci encore! – Brandon