Répertorier uniquement les répertoires utilisant ls dans Bash?

955

Cette commande répertorie les répertoires du chemin actuel: ls -d */

Que fait exactement le motif */ ?

Et comment pouvons-nous donner le chemin absolu dans la commande ci-dessus (par exemple ls -d /home/alice/Documents) pour répertorier uniquement les répertoires de ce chemin?

Sibi
la source
7
Voir la modification de cette réponse unix.stackexchange.com/a/75047/32647 expliquant ce que -dsignifie réellement.
Evgeni Sergeev

Réponses:

993

*/est un modèle qui correspond à tous les sous-répertoires du répertoire en cours ( *correspondrait à tous les fichiers et sous - répertoires; le /restreint aux répertoires). De même, pour répertorier tous les sous-répertoires sous / home / alice / Documents, utilisezls -d /home/alice/Documents/*/

Gordon Davisson
la source
88
Notez que */cela ne correspondra à aucun dossier caché. Pour les inclure, spécifiez-les explicitement comme ls -d .*/ */ou définissez l' dotgloboption dans Bash.
Gergő
1
@ytpillai Cela se produit car il n'y a pas de sous-répertoires à répertorier. Vous obtenez cette erreur chaque fois que vous utilisez lssur quelque chose qui n'existe pas.
Gordon Davisson
1
Très bien merci, je l'ai vérifié tout à l'heure et il s'avère que le seul répertoire est le dossier racine.
ytpillai
1
@GordonDavisson Le message d'échec pourrait être évité avec l'option bashshopt -s nullglob
4
@BinaryZebra La définition de nullglob éviterait le message d'erreur, mais provoquerait encore plus de confusion: avec nullglob défini et sans sous-répertoires, ls */se développerait juste ls, ce qui répertorierait tous les fichiers dans le répertoire en cours. Je suis sûr que ce n'est pas ce que vous voulez dans ce cas.
Gordon Davisson
481

Quatre façons d'y parvenir, chacune avec un format de sortie différent

1. Utilisation echo

Exemple: echo */, echo */*/
Voici ce que je suis:

cs/ draft/ files/ hacks/ masters/ static/  
cs/code/ files/images/ static/images/ static/stylesheets/  

2. Utilisation lsuniquement

Exemple: ls -d */
voici exactement ce que j'ai obtenu:

cs/     files/      masters/  
draft/  hacks/      static/  

Ou sous forme de liste (avec des informations détaillées): ls -dl */

3. Utilisation lsetgrep

Exemple: ls -l | grep "^d" voici ce que j'ai obtenu:

drwxr-xr-x  24 h  staff     816 Jun  8 10:55 cs  
drwxr-xr-x   6 h  staff     204 Jun  8 10:55 draft  
drwxr-xr-x   9 h  staff     306 Jun  8 10:55 files  
drwxr-xr-x   2 h  staff      68 Jun  9 13:19 hacks  
drwxr-xr-x   6 h  staff     204 Jun  8 10:55 masters  
drwxr-xr-x   4 h  staff     136 Jun  8 10:55 static  

4. Bash Script (non recommandé pour les espaces contenant des noms de fichiers)

Exemple: for i in $(ls -d */); do echo ${i%%/}; done
voici ce que j'ai obtenu:

cs  
draft  
files  
hacks  
masters  
static

Si vous aimez avoir '/' comme caractère de fin, la commande sera: for i in $(ls -d */); do echo ${i}; done

cs/  
draft/  
files/  
hacks/  
masters/  
static/
Albert
la source
2
NB. 3était sensiblement plus lent que les autres pour moi. Dans le répertoire que j'ai testé: 1.012s, 2.016s, 3 .055s , 4.021s.
isomorphismes
@isomorphismes, comment avez-vous mesuré le temps? Par quels moyens? Soit dit en passant, je dois dire que non 1est mon préféré.
Albert
Albert, j'ai utilisé timela fonction Unix. /// Je suis d'accord, echo */c'est plus intelligent que ls -d */.
isomorphismes
9
Deux choses mineures à noter. ls -l | grep "^ d" filtre les liens symboliques vers les répertoires, tandis que 'ls -d * /' les affiche. De plus, «ls -d * /» échoue si aucun répertoire n'est présent dans le répertoire cible.
Zoran Pavlovic
15
L' 1.option causera des douleurs importantes lors du traitement des noms de dossiers qui ont des espaces.
Shrikant Sharat
99

J'utilise:

ls -d */ | cut -f1 -d'/'

Cela crée une seule colonne sans barre oblique de fin - utile dans les scripts.

Mes deux centimes.

Thomas Altfather Good
la source
18
L' -1option pour lssera également affichée au format à colonne unique ls -1 -d */.
Kalin
3
@ user29020 Doit noter que génère -1toujours une barre oblique de fin pour chaque entrée.
Dennis
Lorsque j'ajoute cela à un .bashrcalias, comment puis-je l'ajouter '/'?
RNA
@RNA en retard pour répondre, mais pour les futurs: essayez de vous échapper avec une barre oblique inverse? '\/'
Caek
1
Se casse s'il y a une barre oblique. Cela supprime uniquement les barres obliques de fin:| sed -e 's-/$--'
Victor Sergienko
62

Pour tous les dossiers sans sous-dossiers:

find /home/alice/Documents -maxdepth 1 -type d

Pour tous les dossiers avec sous-dossiers:

find /home/alice/Documents -type d
at3m
la source
2
Pour correspondre à la question (mais inclure les fichiers dot), la première devrait être: find /home/alice/Documents -maxdepth 1 -mindepth 1 -type dsinon vous vous incluez /home/alice/Documents. Pour inclure des liens symboliques vers des répertoires, -L
préfixez
Cela semble être la solution la plus saine, car find est l'outil réellement conçu pour cette tâche. Vous pouvez exclure le premier résultat - ./ pour le répertoire actuel - en redirigeant vers grep -v '^ \ ./$'
siliconrockstar
38

4 (plus) Options fiables.

Un astérisque sans guillemets* sera interprété comme un motif (glob) par le shell.
Le shell l'utilisera dans l'extension du nom de chemin.
Il générera ensuite une liste de noms de fichiers correspondant au modèle.
Un simple astérisque correspondra à tous les noms de fichiers dans le PWD (répertoire de travail actuel).
Un modèle plus complexe */qui correspondra à tous les noms de fichiers se terminant par /.
Ainsi, tous les répertoires. C'est pourquoi la commande:

1.- écho.

echo */
echo ./*/              ### avoid misinterpreting filenames like "-e dir"

sera étendu (par le shell) à echotous les répertoires du PWD.


Pour tester cela: créez un répertoire ( mkdir) nommé comme test-dir, et cddans celui-ci:

mkdir test-dir; cd test-dir

Créez des répertoires:

mkdir {cs,files,masters,draft,static}   # safe directories.
mkdir {*,-,--,-v\ var,-h,-n,dir\ with\ spaces}  # some a bit less secure.
touch -- 'file with spaces' '-a' '-l' 'filename'    # and some files:

La commande echo ./*/restera fiable même avec des fichiers nommés étranges:

./--/ ./-/ ./*/ ./cs/ ./dir with spaces/ ./draft/ ./files/ ./-h/
./masters/ ./-n/ ./static/ ./-v var/

Mais les espaces dans les noms de fichiers rendent la lecture un peu déroutante.


Si au lieu de echo, nous utilisons ls, le shell est toujours ce qui élargit la liste des noms de fichiers. Le shell est la raison pour obtenir une liste de répertoires dans le PWD. L' -doption permettant de lsrépertorier l'entrée de répertoire actuelle au lieu du contenu de chaque répertoire (comme présenté par défaut).

ls -d */

Cependant, cette commande est (quelque peu) moins fiable. Il échouera avec les fichiers nommés étranges répertoriés ci-dessus. Il s'étouffera avec plusieurs noms. Vous devez effacer un par un jusqu'à ce que vous trouviez ceux qui ont des problèmes.

2.- ls

Le GNU lsacceptera la --touche "fin des options" ( ).

ls -d ./*/                     ### more reliable BSD ls
ls -d -- */                    ### more reliable GNU ls

3.-printf

Pour répertorier chaque répertoire dans sa propre ligne (dans une colonne, similaire à ls -1), utilisez:

$ printf "%s\n" */        ### Correct even with "-", spaces or newlines.

Et, encore mieux, nous pourrions supprimer la fin /:

$ set -- */; printf "%s\n" "${@%/}"        ### Correct with spaces and newlines.

Une tentative comme celle-ci:

$ for i in $(ls -d */); do echo ${i%%/}; done

Échouera le:

  • certains noms ( ls -d */) comme déjà indiqué ci-dessus.
  • sera affecté par la valeur de IFS.
  • divisera les noms sur les espaces et les tabulations (par défaut IFS).
  • chaque nouvelle ligne du nom lancera une nouvelle commande echo.

4.- Fonction

Enfin, l'utilisation de la liste d'arguments à l'intérieur d'une fonction n'affectera pas la liste d'arguments du shell en cours d'exécution. Simplement:

$ listdirs(){ set -- */; printf "%s\n" "${@%/}"; }
$ listdirs

présente cette liste:

--
-
*
cs
dir with spaces
draft
files
-h
masters
-n
static
-v var

Ces options sont sûres avec plusieurs types de noms de fichiers impairs.


la source
Je pense que vous devriez remplacer le mot Safe par Reliable. Votre message me fait penser que les autres solutions sont «dangereuses» (vulnérables ou exploitables.)
Amado Martinez
1
@AmadoMartinez Fait un général s / sûr / fiable /. Meilleur?
21

La treecommande est également assez utile ici. Par défaut, il affichera tous les fichiers et répertoires à une profondeur complète, avec quelques caractères ascii montrant l'arborescence des répertoires.

$ tree
.
├── config.dat
├── data
   ├── data1.bin
   ├── data2.inf
   └── sql
|      └── data3.sql
├── images
   ├── background.jpg
   ├── icon.gif
   └── logo.jpg
├── program.exe
└── readme.txt

Mais si nous voulions obtenir uniquement les répertoires, sans l'arborescence ascii, et avec le chemin complet du répertoire actuel, vous pourriez faire:

$ tree -dfi
.
./data
./data/sql
./images

Les arguments étant:

-d     List directories only.
-f     Prints the full path prefix for each file.
-i     Makes tree not print the indentation lines, useful when used in conjunction with the -f option.

Et si vous voulez ensuite le chemin absolu, vous pouvez commencer par spécifier le chemin complet vers le répertoire courant:

$ tree -dfi "$(pwd)"
/home/alice/Documents
/home/alice/Documents/data
/home/alice/Documents/data/sql
/home/alice/Documents/images

Et pour limiter le nombre de sous-répertoires, vous pouvez définir le niveau maximum de sous-répertoires avec -L level, par exemple:

$ tree -dfi -L 1 "$(pwd)"
/home/alice/Documents
/home/alice/Documents/data
/home/alice/Documents/images

Plus d'arguments peuvent être vus avec man tree

Hamish Downer
la source
15

Au cas où vous vous demandez pourquoi la sortie de 'ls -d * /' vous donne deux barres obliques de fin, comme:

[prompt]$ ls -d */    
app//  cgi-bin//  lib//        pub//

c'est probablement parce que quelque part votre fichier de configuration shell ou session alias la commande ls vers une version de ls qui inclut l'indicateur -F. Cet indicateur ajoute un caractère à chaque nom de sortie (ce n'est pas un fichier ordinaire) indiquant le genre de chose. Ainsi, une barre oblique est celle correspondant au modèle '* /', et l'autre barre oblique est l'indicateur de type ajouté.

Pour vous débarrasser de ce problème, vous pouvez bien sûr définir un alias différent pour ls. Cependant, pour ne pas invoquer temporairement l'alias, vous pouvez ajouter la barre oblique inverse à la commande:

\ ls -d * /

gwideman
la source
11

Je viens de l'ajouter à mon .bashrcfichier (vous pouvez également le taper sur la ligne de commande si vous en avez besoin / ne le souhaitez que pour une session)

alias lsd='ls -ld */'

alors lsd produira le résultat souhaité.

guesty guesterson
la source
Ne pourriez-vous pas simplement utiliser? ls -l chemin | grep dr
jrobertsz66
5
"alors lsd produira le résultat souhaité." Je ris
fbafelipe
1
D'après mon expérience, cela produit un résultat.
Todd
J'utilise 'lad' (liste tous les répertoires), et j'ai également inclus '. * /' Pour inclure également les répertoires cachés. Bien sûr, les insinuations ne sont pas perdues pour moi non plus.
DryLabRebel
11

lsSolution réelle , y compris les liens symboliques vers les répertoires

De nombreuses réponses ici n'utilisent pas réellement ls(ou ne l'utilisent que dans le sens trivial de ls -d, tout en utilisant des caractères génériques pour la correspondance réelle du sous-répertoire. Une vraie lssolution est utile, car elle permet l'utilisation d' lsoptions pour l'ordre de tri, etc.

Hors liens symboliques

Une solution utilisant lsa été donnée, mais elle fait quelque chose de différent des autres solutions en ce qu'elle exclut les liens symboliques vers les répertoires:

ls -l | grep '^d'

(éventuellement passe à travers sedouawk pour isoler les noms de fichiers)

Y compris les liens symboliques

Dans le cas (probablement plus courant) où des liens symboliques vers des répertoires devraient être inclus, nous pouvons utiliser l' -poption de ls, ce qui fait qu'il ajoute un caractère barre oblique aux noms des répertoires (y compris les liens symboliques):

ls -1p | grep '/$'

ou, en supprimant les barres obliques de fin:

ls -1p | grep '/$' | sed 's/\/$//'

Nous pouvons ajouter des options au lsbesoin (si une longue liste est utilisée, la -1n'est plus requise).

Remarque: si nous voulons des barres obliques de fin, mais que nous ne voulons pas qu'elles soient mises en évidence par grep, nous pouvons supprimer de manière piratée la mise en surbrillance en rendant la partie correspondante de la ligne vide:

ls -1p | grep -P '(?=/$)'
pyrocrastie
la source
9

S'il n'est pas nécessaire que le répertoire caché soit répertorié, je propose:

ls -l | grep "^d" | awk -F" " '{print $9}'  

Et si des répertoires cachés doivent être répertoriés, utilisez:

ls -Al | grep "^d" | awk -F" " '{print $9}'

OU

find -maxdepth 1 -type d | awk -F"./" '{print $2}'
Apprenant PHP
la source
Si vous avez besoin d'en savoir plus awk, consultez cette réponse
PHP Learner
Par rapport aux autres réponses, la première option de "ls .. | grep ... | awk" semble un script excessif.
Lars Nordin
1
Vous supposez qu'aucun répertoire ne comporte d'espaces à l'intérieur de leurs noms.
Benjamin R
7

pour afficher les listes de dossiers sans /

ls -d */|sed 's|[/]||g'
Wholanda
la source
2
ouls -d1 */ | tr -d "/"
ccpizza
Pas besoin d'appeler une commande externe:set -- */; printf "%s\n" "${@%/}"
J'aime la solution de @wholanda. Ma solution un peu plus courte est (testée et fonctionne): ls -d * / | sed's | / || g '
klor
Il est également utile d'avoir un alias lsdir: alias lsdirs = "ls -d * / | sed's | / || g '"
klor
6

Voici ce que j'utilise

ls -d1 /Directory/Path/*;

Interdiction
la source
C'est en fait une assez bonne solution pour l'afficher ligne par ligne.
Nikolay Frick
Il ne répertorie pas uniquement les répertoires. Vous devez ajouter une barre oblique de fin:ls -d1 /Directory/Path/*/
Skippy le Grand Gourou
6

Pour répertorier uniquement les répertoires :

ls -l | grep ^d

pour répertorier uniquement les fichiers :

ls -l | grep -v ^d 

ou vous pouvez aussi faire comme: ls -ld * /

Vijay Gawas
la source
4

Testez si l'élément est un répertoire avec test -d:

for i in $(ls); do test -d $i && echo $i ; done
nmarques
la source
1
Veuillez expliquer ce que fait ce code et comment il se rapporte à la question.
Ken YN
1
il exécute la commande 'ls', puis passe en revue le test de sortie si chacun est un répertoire et fait écho s'il l'est .. fonctionne mais il existe de meilleures façons
ShoeLace
3

*/ est un modèle de correspondance de nom de fichier qui correspond aux répertoires du répertoire actuel.

Pour ne lister que les répertoires, j'aime cette fonction:

# long list only directories
llod () { 
  ls -l --color=always "$@" | grep --color=never '^d'
}

Mettez-le dans votre .bashrc.

Exemples d'utilisation:

llod       # long listing of all directories in current directory
llod -tr   # same but in chronological order oldest first
llod -d a* # limit to directories beginning with letter 'a'
llod -d .* # limit to hidden directories

REMARQUE: il se cassera si vous utilisez l' -ioption. Voici un correctif pour cela:

# long list only directories
llod () { 
  ls -l --color=always "$@" | egrep --color=never '^d|^[[:digit:]]+ d'
}
Robin A. Meade
la source
3

Pour info, si vous souhaitez imprimer tous les fichiers sur plusieurs lignes, vous pouvez faire un ls -1qui imprimera chaque fichier sur une ligne distincte. fichier1 fichier2 fichier3

warfreak92
la source
3

Une simple liste du répertoire courant, ce serait:

ls -1d ./*/

Voulez-vous qu'il soit trié et propre?

ls -1d ./*/ | cut -c 3- | rev | cut -c 2- | rev | sort

Rappelez-vous: les caractères en majuscule ont un comportement différent dans le tri

PYK
la source
3

Essaye celui-là. Cela fonctionne pour toutes les distributions Linux.

ls -ltr | grep drw
Raj RD
la source
4
ls -l | grep '^d' | awk '{print $9}'
dw1
2

One-liner pour lister les répertoires uniquement "d'ici".

Avec le nombre de fichiers.

for i in `ls -d */`; do g=`find ./$i -type f -print| wc -l`; echo "Directory $i contains $g files."; done
BHG
la source
2

J'ai résolu partiellement avec:

cd "/path/to/pricipal/folder"

for i in $(ls -d .*/); do sudo ln -s "$PWD"/${i%%/} /home/inukaze/${i%%/}; done

ln: «/home/inukaze/./.»: can't overwrite a directory
ln: «/home/inukaze/../..»: can't overwrite a directory
ln: accesing to «/home/inukaze/.config»: too much symbolics links levels
ln: accesing to «/home/inukaze/.disruptive»: too much symbolics links levels
ln: accesing to «/home/inukaze/innovations»: too much symbolics links levels
ln: accesing to «/home/inukaze/sarl»: too much symbolics links levels
ln: accesing to «/home/inukaze/.e_old»: too much symbolics links levels
ln: accesing to «/home/inukaze/.gnome2_private»: too much symbolics links levels
ln: accesing to «/home/inukaze/.gvfs»: too much symbolics links levels
ln: accesing to «/home/inukaze/.kde»: too much symbolics links levels
ln: accesing to «/home/inukaze/.local»: too much symbolics links levels
ln: accesing to «/home/inukaze/.xVideoServiceThief»: too much symbolics links levels

Eh bien, cela me réduit, la partie maire :)

inukaze
la source
2

Ajouter pour faire le tour complet, pour récupérer le chemin de chaque dossier, utilisez une combinaison de la réponse d'Albert ainsi que de Gordans qui devrait être assez utile.

for i in $(ls -d /pathto/parent/folder/*/); do echo ${i%%/}; done

Production:

/pathto/parent/folder/childfolder1/
/pathto/parent/folder/childfolder2/
/pathto/parent/folder/childfolder3/
/pathto/parent/folder/childfolder4/
/pathto/parent/folder/childfolder5/
/pathto/parent/folder/childfolder6/
/pathto/parent/folder/childfolder7/
/pathto/parent/folder/childfolder8/
BilliAm
la source
2

Utilisation de Perl:

ls | perl -nle 'print if -d;'
Paul-Gerhard Woolcock
la source
1

Voici ce que j'utilise pour répertorier uniquement les noms de répertoire:

ls -1d /some/folder/*/ | awk -F "/" "{print \$(NF-1)}"
Robert Lujo
la source
1

Pour répondre à la question d'origine, cela */n'a rien à voir avec en lssoi; cela se fait par le shell / Bash, dans un processus appelé globbing .

C'est pourquoi echo */et ls -d */sortir les mêmes éléments. (L' -dindicateur fait lssortir les noms de répertoires et non le contenu des répertoires.)

flow2k
la source
1

Voici une variante utilisant l'arborescence qui ne sort les noms de répertoire que sur des lignes séparées, oui c'est moche mais bon, ça marche.

tree -d | grep -E '^[├|└]' | cut -d ' ' -f2

ou avec awk

tree -d | grep -E '^[├|└]' | awk '{print $2}'

C'est probablement mieux cependant et conservera le /nom du répertoire après.

ls -l | grep "^d" | awk '{print $9}'
lacostenycoder
la source
cela ressemble au coréen!
Paschalis
0
file *|grep directory

O / P (Sur ma machine) -

[root@rhel6 ~]# file *|grep directory
mongo-example-master:    directory
nostarch:                directory
scriptzz:                directory
splunk:                  directory
testdir:                 directory

La sortie ci-dessus peut être affinée davantage en utilisant la découpe.

file *|grep directory|cut -d':' -f1
mongo-example-master
nostarch
scriptzz
splunk
testdir

* could be replaced with any path that's permitted
 file - determine file type
 grep - searches for string named directory
 -d - to specify a field delimiter
 -f1 - denotes field 1
AVS
la source
0

La commande la plus courte jamais (en fait un hack) pour lister uniquement les répertoires. Tapez le chemin absolu ou le chemin relatif du répertoire d'intérêt et appuyez sur Entrée pour entrer dans le répertoire d'intérêt. Maintenant, tapez cdet appuyez sur la touche de tabulation . Seuls les répertoires sont affichés maintenant.

user@ubuntu:~/Desktop$cd <tab key>

La commande ci-dessus ne devrait désormais afficher que les dossiers du bureau . Le plus court en effet.

Prométhée
la source
Cela suppose que la saisie semi-automatique est activée et peut ne pas fonctionner dans tous les cas. De plus, si vous vouliez faire quelque chose avec cela, comme diriger la sortie vers quelque chose, cela ne fonctionnera pas. Mais juste pour voir la sortie, cela fonctionne rapidement et facilement.
lacostenycoder
Parfait! J'ai supprimé le "." Et puis cela a fonctionné
user2060451