def prody_catdcd(*dcd, **kwargs):
    """Concatenate *dcd* files.

    :arg select: atom selection

    :arg align: atom selection for aligning frames

    :arg pdb: PDB file used in atom selections and as reference for alignment

    :arg psf: PSF file used in atom selections

    :arg output: output filename

    :arg first: index of the first output frame

    :arg last: index of the last output frame

    :arg stride: number of steps between output frames"""
    import prody
    LOGGER = prody.LOGGER
    if kwargs.get('numframes', False):
        from sys import stdout
        for fn in dcd:
            stdout.write(str(prody.DCDFile(fn).numFrames()) + '\n')
        return
    from os.path import splitext
    ag = None
    psf = kwargs.get('psf', None)
    if psf:
        ag = prody.parsePSF(psf)
    pdb = kwargs.get('pdb', None)
    if pdb:
        if ag:
            ag = prody.parsePDB(pdb, ag=ag)
        else:
            ag = prody.parsePDB(pdb)
    align = kwargs.get('align', None)
    select = kwargs.get('select', None)
    if select == 'all':
        select = None
    if ag is None and (align or select):
        raise ValueError(
            'one of PSF or PDB files must be provided for align and select options to work'
            )
    dcd = list(dcd)
    traj = prody.Trajectory(dcd.pop(0))
    while dcd:
        traj.addFile(dcd.pop(0))
    if ag:
        traj.link(ag)
        if ag.numCoordsets():
            traj.setCoords(ag.getCoords())
        if select:
            select = ag.select(select)
            if select is None:
                raise ValueError('{0} did not match any atoms'.format(repr(
                    kwargs.get('select'))))
        else:
            select = ag
        LOGGER.info('{0} atoms are selected for writing output.'.format(len
            (select)))
        if align:
            align = ag.select(align)
            traj.setAtoms(align)
            LOGGER.info('{0} atoms are selected for aligning frames.'.
                format(len(align)))
    output = kwargs.get('output', 'trajectory.dcd')
    out = prody.DCDFile(output, 'w')
    count = 0
    stride = kwargs.get('stride', 1)
    goto = stride != 1
    slc = slice(kwargs.get('first', 0), kwargs.get('last', -1), stride
        ).indices(len(traj) + 1)
    for i in range(*slc):
        if goto:
            traj.goto(i)
        frame = next(traj)
        if align:
            frame.superpose()
        if select:
            out.write(select._getCoords(), frame.getUnitcell())
        else:
            out.write(frame._getCoords(), frame.getUnitcell())
        count += 1
    traj.close()
    out.close()
    LOGGER.info('{0} frames are written into {1}.'.format(count, output))
