|
|
|
|
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
Configuration: Linux Firefox 3.0.4
En fait ça dépend pas mal des conventions de nommage de tes fichiers, notamment :
|
Bonjour, et merci de cette reponse !
|
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 |