Commande ls modifiee

Fermé
ludo - 1 juil. 2009 à 16:00
 ludo - 3 juil. 2009 à 18:44
Bonjour,

j'aimerais creer une commande du genre ls mais un peu differente, je travaille avec des sequences d'images numerotees (des centaines) et j'aimerais qu'elles soient listees par nom.
Un exemple vaut milles mots :
ls de base :

~/plate $ ls
product.0001.iff
product.0002.iff
product.0003.iff
product.0004.iff
product.0005.iff
product.0006.iff

ce que je voudrait obtenir :

~/plate $ superls
product.[0001,0006].iff

Merci de votre aide !!
Ludovic

3 réponses

mamiemando Messages postés 33357 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 13 novembre 2024 7 805
2 juil. 2009 à 13:43
En fait ça dépend pas mal des conventions de nommage de tes fichiers, notamment :
- est-ce qu'on les agrège systématiquement sur ce qui n'est pas une valeur numérique,
- est ce que d'autres valeurs numériques peuvent figurer dans le nom du fichier,
- comment doit réagir le fichier si j'ai pouet1, pouet2, pouet4 pouett5 mais pas pouet3 ?

Une fois que tu auras répondu à ces questions, le plus simple c'est d'écrire un petit script shell / python / perl ou ruby selon l'outil que tu préfères.

Une autre solution serait peut être aussi de trier tes images... par répertoire ;-)

Bonne chance
0
Bonjour, et merci de cette reponse !

Par convention le nom de fichiers d'images s'ecrivent comme suit :
nom_du_fichier.####.ext (le nombre de # correspond au padding et peut varier de 1 a 6)
la numerotation des images se trouvent donc entre deux separateur "."

- on agrege sur tout ce qui n'est pas compris entre les deux points
- d'autres valeurs numeriques pourraient figurer dans le nom du fichier
- et si il manque un fichier l'ideal serait que l'on obtiennent quelquechose comme ca :

product.0001.iff
product.0002.iff
product.0003.iff

product.0005.iff
product.0006.iff
product.0007.iff
product.0008.iff
toto.txt
lolo.0001.jpg
lolo.0002.jpg
lolo.0003.jpg
lolo.0004.jpg
lolo.0005.jpg

ce que je voudrait obtenir :

~/plate $ superls
product.[0001,0003].iff
product.[0005,0008].iff
toto.txt
lolo.[0001,0005].jpg

concernat le tri par repertoire, c'est bien sur la solution la plus simple, mais ce n'est pas toujours le cas... independament de ma volonte, d'autre part cet outil serait tres utile pour reperer les images manquantes dans une tres longue sequence.

je ne connais rien dans l'ecriture de scripts pour linux (les seuls que j'ai ecris etaient en jscript et pour des logiciels de 3d...) alors si vous pouvez m'orienter dans le choix des outils et commandes...
Merci beaucoup, et bonne journee.

Ludo
0
mamiemando Messages postés 33357 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 13 novembre 2024 7 805
3 juil. 2009 à 00:33
Voici le genre de programme que tu peux écrire en C++ (appelle ce fichier par exemple super_ls.cpp). Il y avait sûrement plus simple avec des langages comme python ruby ou perl mais je n'ai pas spécialement le courage de chercher :
#include <iostream>
#include <ostream>
#include <fstream>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <map>
#include <set>
#include <pcre.h>

#define OV_LENGTH 200

// Implémentation expression régulière

namespace detail {
    static const char *pcre_error = NULL;
    static int pcre_error_offset = 0;

    inline const ::pcre* make_re(
        const char * str,
        bool is_caseless
    ){
        const ::pcre* pre = pcre_compile(str, is_caseless ? PCRE_CASELESS : 0, &pcre_error, &pcre_error_offset, NULL);
        if( pre==NULL ){
            std::cerr << "PCRE ERROR :" << std::endl << str << std::endl;
            std::cerr << std::string( pcre_error_offset, ' ' ) << "^" << std::endl;
            std::cerr << pcre_error << std::endl;
        }
        return pre;
    }

    inline int  match(const ::pcre* regex,int * ov, const std::string   & line){
        int res = pcre_exec( regex, NULL, line.c_str(), line.size( ), 0, 0, ov, OV_LENGTH );
        return res;
    }

    inline std::string get_str(const std::string & line,int * ov,int idx){
        if( ov[idx*2+2]<0 || ov[idx*2+3]>static_cast<int>(line.size( )) || ov[idx*2+2]>ov[idx*2+3] ) return "";
        std::string s = line.substr( ov[idx*2+2], ov[idx*2+3]-ov[idx*2+2] ), r="";
        return s;
    }

    inline long get_long(std::string const & line,int *ov,int idx){
        return atoi(get_str( line,ov, idx ).c_str() );
    }
}


// Binding avec la librarie PCRE

class regexp
{
    protected:
        const ::pcre *  m_m;
        std::string m_e;
        int ov[OV_LENGTH];
        std::string was_matched;

        inline void makere(const std::string & expr){
            if(expr.size() == 0) return;
            m_m = detail::make_re(expr.c_str(),true);
            if (m_m != NULL) m_e = expr;
        }
    public:
        regexp() : m_m(NULL),m_e("") { }

        regexp(const std::string & expr)
            : m_m(NULL),m_e("")
        {
            makere(expr);
        }

        regexp(const regexp & x)
            : m_m(NULL),m_e("")
        {
            makere(x.m_e);
        }

        inline int match(const std::string & l){
            int res = detail::match(m_m,ov,l);
            was_matched = l;
            return res - 1;
        }

        inline std::string get_str(std::size_t idx){
            return detail::get_str(was_matched,ov,idx);
        }

        inline long get_long(std::size_t idx){
            return detail::get_long(was_matched,ov,idx);
        }
};

inline void write_super_filename(std::ostream & out,const std::string & key,long first,long last,const std::string & ext){
    out << key << ".[" << first << "," << last << "]." << ext << std::endl;
}

int main(int argc,char **argv){
    // Vérifier les arguments
    if(argc != 2){
        std::cerr << "usage: " << argv[0] << " filename" << std::endl;
        return 1;
    }

    // Ouvrir le fichier
    std::ifstream ifs(argv[1]);
    if(!ifs){
        std::cerr << "can't read " << argv[1] << std::endl;
        return 2;
    }

    // Stocker dans une map la liste des fichiers
    std::string line;
    typedef std::map<std::string,std::map<std::string,std::set<long> > > my_map_t;
    my_map_t my_map;
    static regexp regexp_filename("^(\\S+)\\.(\\d+)\\.(\\S+)$");
    while(std::getline(ifs,line)){
        if(regexp_filename.match(line) == 3){
            std::string key = regexp_filename.get_str(0);
            long id = regexp_filename.get_long(1);
            std::string ext = regexp_filename.get_str(2);
            my_map[key][ext].insert(id);
        }
    }
    // Parcourir la map
    my_map_t::const_iterator
        mit (my_map.begin()),
        mend(my_map.end());
    for(;mit!=mend;++mit){
        const std::string & key = mit->first;
        const std::map<std::string,std::set<long> > & sub_map = mit->second;
        std::map<std::string,std::set<long> >::const_iterator
            mit2 (sub_map.begin()),
            mend2(sub_map.end());
        for(;mit2!=mend2;++mit2){
            const std::string & ext = mit2->first;
            const std::set<long> & ids = mit2->second;
            if(!ids.empty()){
                std::set<long>::const_iterator
                    sit (ids.begin()),
                    send(ids.end());
                long first = *ids.begin();
                long last = first;
                for(;sit!=send;++sit){
                    long id_cur = *sit;
                    if (id_cur - 1 != last && id_cur != last){
                        write_super_filename(std::cout,key,first,last,ext);
                        first = id_cur;
                    }
                    last = id_cur;
                }
                write_super_filename(std::cout,key,first,last,ext)
            }
        }
    }

    // Fermer le fichier
    ifs.close();
    return 0;
}


Pour le compiler il faut installer libpcre3-dev et taper :
g++ -W -Wall super_ls.cpp -o super_ls -lpcre

Mets le résultat de ton ls dans un fichier :
ls -1 > ls.txt
./super_ls ls.txt

Exemple :
(mando@aldur) (~) $ cat ls.txt
product.0001.iff
product.0002.iff
product.0003.iff
product.0005.iff
product.0006.iff
product.0007.iff
product.0008.iff
toto.txt
lolo.0001.jpg
lolo.0002.jpg
lolo.0003.jpg
lolo.0004.jpg
lolo.0005.jpg
(mando@aldur) (~) $ ./super_ls ls.txt
lolo.[1,5].jpg
product.[1,3].iff
product.[5,8].iff

Libre à toi de wrapper tout ça dans un script shell pour éviter de passer par un fichier ls.txt :
#!/bin/sh
# super_ls.sh
tmpfile="/tmp/super_ls"
ls -1 $1 > $tmpfile
/le/chemin/vers/super_ls $tmpfile
rm $tmpfile

... et de mettre ce script dans un des répertoires précisé dans cette variable d'environnement :
echo $PATH

... pour n'avoir à taper que :
super_ls.sh /mon/repertoire

Bonne chance
0
Merci beaucoup !

Je vais étudier ça de près.
Ça va me permettre de comprendre et d'apprendre beaucoup de chose, vraiment très apprécié !!

Bye.
Ludo
0