Quick Tour ========== .. _as-cli: As Commandline Tool ------------------- Once you install FsQuass, it can work as command line tool. It's almost like `GNU find `_, except that it *only searches* and does not try to be a Swiss knife. There are no options in it:: $ fsquass '/home/*' /home/siberiano /home/guest :note: It's better to quote the arguments since Bash may try to convert masks (``*``, ``.``) for you. If you need to do something with the found files, use ``xargs``:: $ fsquass '/home .bashrc' | xargs cat This prints the contents of all .bashrc files :ref:`descendants` of user folders. As a quick tip on xargs, to pass file path in the middle of a command, use curly braces:: $ fsquass '/home .bashrc' | xargs -I '{}' ln -S {} /tmp To each found ``.bashrc`` this will make a symlink in ``/tmp``. .. _as-module: As a Python Module ------------------ The :py:class:`Fs ` class (stands for *files set*), like jQuery, searches by string and also inherits the API of :py:class:`set` class with all set operations: union, intersection, add, remove, etc. .. code-block:: python from fsquass import Fs Fs('/home .bashrc') - Fs('~/.bashrc') # similar to jQuery.not() File sets are iterable and consist of :py:class:`File ` or :py:class:`Dir ` instances. They also can generate strings: .. code-block:: python for project in Fs('~/projects/*'): print project for path in Fs('~/projects/*'): # a generator of string paths print path .. _syntax: Syntax ------ The syntax is essentially Unix filename patterns + some powerful extensions. Patterns work via :py:mod:`fnmatch` module. The special characters used in shell-style wildcards are: ``*``, ``?`` (any single character), ``[abc]`` (a, b or c), ``[!abc]`` anything but them. Some simple examples:: folder/folder/file.py[co] folder/*/*.txt /etc/hosts /var/log/*.log ./file file ../another_folder/file The two latter examples are the same. But here come some extensions: you can go a level up from a file:: fsquass/setup.py/.. This expression will evaluate to ``fsquass``, but only if ``setup.py`` is present. This is useful if you need folders to contain specific children. .. _descendants: Descendants ~~~~~~~~~~~ It works like in CSS:: ~ *.py will search for ``*.py`` anywhere in the home folder, at any folders depth. :attention: This kind of search is expensive since it makes the program go through all the directory tree down from ``~``. Make such searches as narrow as possible if you can: ``*/projects/django *.py``. You can make several such searches:: ~/projects templates *.haml Scans ``projects`` folder for ``templates``, then scans each of those for ``*.haml``. The second part of descendant can be multi-level:: ~/projects templates/*.haml Use backslash to write a space in a name. Use double backslash if you need to escape the backslash itself:: ~/project\ description/* Yet there is no syntax for the opposite search, for random number of levels upwards. .. pseudoclass: Pseudo-Classes ~~~~~~~~~~~~~~ Similar to those in CSS, they are written in the end or instead of a pattern, and either filter filesystem objects by type, or modify the pattern's properties: +-----------------+-------------------------------+ | Pseudo-Class | Meaning | +=================+===============================+ | ``:file`` | object is a file | +-----------------+-------------------------------+ | ``:dir`` | object is a directory | +-----------------+-------------------------------+ | ``:ignorecase`` | makes search case-insensitive | +-----------------+-------------------------------+ Examples:: ~/.*:dir ~/*:file /home/:dir /:dir ~/Pictures *.jpg:ignorecase .. _sub-patterns: Sub-Patterns ~~~~~~~~~~~~ In Unix shell, you can do this: ``mkdir project/{apps,templates,static}``. The same works in fsquass. Between slashes, you can use curly braces to write multiple options:: /home/{siberiano,guest}/.bashrc ~/Pictures {*.jpeg:ignorecase,*.jpg:ignorecase} :note: Pseudo-classes must be inside the curly braces. .. _multiple-patterns: Multiple Patterns ~~~~~~~~~~~~~~~~~ If you need to find objects with completely different paths or patterns, write multiple expressions separated with a colon:: /etc/hosts;~/.my_hosts;~/test.txt Put a backslash to a colon if it's a part of a name:: strange\;name1;strange\;name2 .. _set-operations: Set Operations -------------- :py:class:`Fs ` inherits from :py:class:`set` and suspports all the set methods. .. code-block:: python Fs('./*.py') | Fs('./*.pyc') # union Fs('. {*.rst,*.txt}') - Fs('./build *.txt') # not Fs('*.py') & Fs('__*__.py') # intersection Fs('*.py') ^ Fs('__*__.py') # xor (union not intersection) :py:func:`filter ` is just like interection, but is faster since it doesn't search files on disk. .. code-block:: python Fs('*.py').filter('__*__.py') .. _traversing: Traversing ---------- Having one set of files you can generate another set relative of it: .. code-block:: python # find Python scripts and then their parent folders that start with 'django' django_projects = Fs('~/projcets *.py').parents('django*') # inside those find __init__.py at top level django_projects.children('__init__.py') # or at any depth django_projects.find('. __init__.py') # find doc roots inside them, by relative path (no recursive search) django_projects.find('docs/source/index.*') django_projects.siblings() .. _manipulation: Files Manipulation ------------------ Currently :py:class:`Fs ` supports * :py:func:`linkTo ` * :py:func:`symlinkTo `