web-dev-qa-db-fra.com

Comment joindre plusieurs lignes de noms de fichiers en une seule avec un délimiteur personnalisé?

J'aimerais joindre le résultat de ls -1 en une ligne et le délimiter avec tout ce que je veux.

Existe-t-il des commandes Linux standard que je peux utiliser pour y parvenir?

379
JavaRocky

Semblable à la toute première option mais en omettant le délimiteur final

ls -1 | paste -sd "," -
586
Artem

EDIT: Simplement "ls -m" Si vous voulez que votre délimiteur soit une virgule

Ah, le pouvoir et la simplicité!

ls -1 | tr '\n' ','

Changez la virgule "," en ce que vous voulez. Notez que cela inclut une "virgule de fin"

353
zaf

Ceci remplace la dernière virgule par une nouvelle ligne:

ls -1 | tr '\n' ',' | sed 's/,$/\n/'

ls -m inclut les nouvelles lignes au caractère de largeur d'écran (80e par exemple).

Principalement Bash (uniquement ls est externe):

saveIFS=$IFS; IFS=$'\n'
files=($(ls -1))
IFS=,
list=${files[*]}
IFS=$saveIFS

Utilisation de readarray (alias mapfile) dans Bash 4:

readarray -t files < <(ls -1)
saveIFS=$IFS
IFS=,
list=${files[*]}
IFS=$saveIFS

Merci à gniourf_gniourf pour les suggestions.

24

Je pense que celui-ci est génial

ls -1 | awk 'ORS=","'

ORS est le "séparateur d'enregistrement de sortie". Vos lignes seront donc jointes par une virgule.

19
majkinetor

La combinaison du réglage IFS et de l'utilisation de "$*" peut faire ce que vous voulez. J'utilise un sous-shell afin que je n'interfère pas avec le $ IFS de ce shell

(set -- *; IFS=,; echo "$*")

Pour capturer la sortie,

output=$(set -- *; IFS=,; echo "$*")
14
glenn jackman

Analyser ls en général n'est pas conseillé , la meilleure façon de procéder consiste donc à utiliser find, par exemple:

find . -type f -print0 | tr '\0' ','

Ou en utilisant find et paste:

find . -type f | paste -d, -s

Pour joindre en général plusieurs lignes (sans lien avec le système de fichiers), vérifiez: "jointure" concise et portable sur la ligne de commande Unix .

13
kenorb

Ne réinventez pas la roue.

ls -m

C'est exactement ça.

9
Tulains Córdova

Cette commande est pour les fans de Perl:

ls -1 | Perl -l40pe0

Ici 40 est le code ascii octal pour l'espace.

-p traitera ligne par ligne et imprimera

-l prendra soin de remplacer le\n trailing par le caractère ascii que nous fournissons.

-e est d'informer Perl que nous sommes en train d'exécuter la ligne de commande.

0 signifie qu'il n'y a en réalité aucune commande à exécuter.

Perl -e0 est identique à Perl -e ''

7

juste bash

mystring=$(printf "%s|" *)
echo ${mystring%|}
7
ghostdog74

Pour éviter une éventuelle confusion de nouvelle ligne pour tr, nous pourrions ajouter le drapeau -b à ls:

ls -1b | tr '\n' ';'
6
yabt

Il semble que les réponses existent déjà.

Si vous voulez le format a, b, c, utilisez ls -m ( réponse de Tulains Córdova )

Ou si vous voulez le format a b c, utilisez ls | xargs (version simplifiée de réponse de Chris J )

Ou si vous voulez un autre délimiteur comme |, utilisez ls | paste -sd'|' (application de réponse d'Artem )

4
plhn
sed -e :a -e '/$/N; s/\n/\\n/; ta' [filename]

Explication:

-e - indique une commande à exécuter
:a - est une étiquette
/$/N - définit l'étendue de la correspondance pour la ligne courante et la ligne (N) ext
s/\n/\\n/; - remplace tous les EOL par \n
ta; - mentionne a si la correspondance est réussie

Tiré de mon blog .

3
Anand Rajasekar

Si votre version de xargs prend en charge l'indicateur -d, cela devrait fonctionner

ls  | xargs -d, -L 1 echo

-d est le drapeau délimiteur

Si vous n'avez pas -d, alors vous pouvez essayer ce qui suit

ls | xargs -I {} echo {}, | xargs echo

Le premier xargs vous permet de spécifier votre délimiteur qui est une virgule dans cet exemple.

3
Chris J

La voie sed,

sed -e ':a; N; $!ba; s/\n/,/g'
  # :a         # label called 'a'
  # N          # append next line into Pattern Space (see info sed)
  # $!ba       # if it's the last line ($) do not (!) jump to (b) label :a (a) - break loop
  # s/\n/,/g   # any substitution you want

Remarque :

Cette complexité est linéaire et ne remplace qu'une seule fois après l'ajout de toutes les lignes dans l'espace des motifs de sed.

@ (AnandRajaseka) réponse , et quelques autres réponses similaires, telles que ici , sont O (n²), car sed doit se substituer à chaque fois qu'une nouvelle ligne est ajoutée au motif Espace.

Comparer,

seq 1 100000 | sed ':a; N; $!ba; s/\n/,/g' | head -c 80
  # linear, in less than 0.1s
seq 1 100000 | sed ':a; /$/N; s/\n/,/; ta' | head -c 80
  # quadratic, hung
3
zhazha

Vous pouvez utiliser:

ls -1 | Perl -pe 's/\n$/some_delimiter/'
2
codaddict

ls produit une sortie de colonne lorsqu'il est connecté à un tuyau, ainsi le -1 est redondant.

Voici une autre réponse Perl utilisant la fonction intégrée join qui ne laisse pas de délimiteur final:

ls | Perl -F'\n' -0777 -anE 'say join ",", @F'

L'obscur -0777 permet à Perl de lire toutes les entrées avant d'exécuter le programme.

alternative sed qui ne laisse pas de délimiteur final

ls | sed '$!s/$/,/' | tr -d '\n'
2
Thor

Ajoutant en plus de la réponse de majkinetor, voici la manière de supprimer le délimiteur final (car je ne peux pas encore commenter sous sa réponse):

ls -1 | awk 'ORS=","' | head -c -1

Supprimez simplement autant d'octets de fin que votre délimiteur compte.

J'aime cette approche car je peux utiliser des délimiteurs multi-caractères + d'autres avantages de awk:

ls -1 | awk 'ORS=", "' | head -c -2

EDIT

Comme Peter l’a remarqué, le nombre d’octets négatifs n’est pas pris en charge dans la version MacOS native de head. Cela peut cependant être facilement corrigé.

Tout d'abord, instal coreutils. "Les GNU Core Utilities sont les utilitaires de base de fichiers, de shell et de manipulation de texte du système d'exploitation GNU."

brew install coreutils

Les commandes également fournies par MacOS sont installées avec le préfixe "g". Par exemple, gls.

Une fois que cela est fait, vous pouvez utiliser ghead qui a un nombre d'octets négatif ou supérieur, créez un alias:

alias head="ghead"

ls a l'option -m pour délimiter la sortie avec ", " une virgule et un espace.

ls -m | tr -d ' ' | tr ',' ';'

si ce résultat est acheminé à tr pour supprimer l’espace ou la virgule, vous pourrez rediriger le résultat vers tr pour remplacer le délimiteur.

dans mon exemple, je remplace le délimiteur , par le délimiteur ;

remplacez ; par quoi que ce soit n séparateur de caractères vous préférez, car tr ne rend compte que du premier caractère des chaînes que vous transmettez en tant qu'arguments.

0
Andy

Vous pouvez utiliser chomp pour fusionner plusieurs lignes en une seule ligne:

Perl -e 'while (<>) {if (/\$ /) {chomp; } print;} 'bad0> test

mettez la condition de saut de ligne dans l'instruction if.Il peut s'agir d'un caractère spécial ou de tout délimiteur.

0
Suman

Version Quick Perl avec gestion des slash de fin:

ls -1 | Perl -E 'say join ", ", map {chomp; $_} <>'

Expliquer:

  • Perl -E: exécute Perl avec des fonctionnalités supportées (par exemple, ...)
  • dire: imprimer avec un retour de transporteur
  • join ",", ARRAY_HERE: joint un tableau avec ","
  • map {chomp; $ _} ROWS: supprime de chaque ligne le transporteur retourne et retourne le résultat
  • <>: stdin, chaque ligne est une ligne, couplée à une carte, elle crée un tableau de chaque ligne
0
Celogeek San