Wie füge ich mehrere Zeilen mit Dateinamen mit einem benutzerdefinierten Trennzeichen zu einer zusammen?


441

Ich möchte das Ergebnis von ls -1in einer Zeile zusammenfassen und es mit dem abgrenzen, was ich will.

Gibt es Standard-Linux-Befehle, mit denen ich dies erreichen kann?

Antworten:


689

Ähnlich wie bei der allerersten Option, lässt jedoch das nachfolgende Trennzeichen weg

ls -1 | paste -sd "," -

29
Nur als Hinweis: Für die Version von Paste, die ich ausprobiert habe, ist am Ende ein "-" - Argument erforderlich, damit sie von STDIN gelesen werden kann. zB ls -1 | paste -s -d ":" - Nicht sicher, ob das bei allen Versionen von Paste universell ist
Andy White

4
Dieser ist besser, weil er ein leeres Trennzeichen zulässt :)
Yura Purbeev

2
Hinweis pasteerhält -(Standardeingabe) als Standard, zumindest auf meinem paste (GNU coreutils) 8.22.
Fedorqui 'SO hör auf zu schaden'

1
Ich habe es gerade positiv bewertet, dies ist und jetzt hat es die gleichen Stimmen wie die ausgewählte Antwort. DAS IST DIE ANTWORT. kein nachlaufender Delimeter
thebugfinder

1
Das leere Trennzeichen kann mit angegeben werden "\0", also paste -sd "\0" -für mich gearbeitet!
Brad Parks

378

EDIT : Einfach " ls -m " Wenn Sie möchten, dass Ihr Trennzeichen ein Komma ist

Ah, die Kraft und Einfachheit!

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

Ändern Sie das Komma " , " nach Belieben. Beachten Sie, dass dies ein "nachfolgendes Komma" enthält.


46
+1, aber eine ausgefeiltere Version sollte last \ n anders behandeln
mouviciel

5
Wenn der Dateiname ein enthält \n, wird dies ebenfalls ersetzt.
Codaddict

3
@ShreevatsaR: Er meint, kein nachfolgendes "," anzuhängen, glaube ich. wie sols -1 | tr "\\n" "," | sed 's/\(.*\),/\1/'
Chris

7
@ Chris: Sie sedkönnten ein wenig effizienter mit dem ls -1 | tr "\\n" "," | sed 's/,$//'; echo ''
Endmarker

2
Die Verwendung von sedafter trscheint nur das letzte Symbol zu entfernen, was unvernünftig erscheint. Ich gehe mitls -1 | tr '\n' ',' | head -c -1
reddot

29

Dies ersetzt das letzte Komma durch eine neue Zeile:

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

ls -m Enthält Zeilenumbrüche am Zeichen für die Bildschirmbreite (z. B. 80.).

Meistens Bash (nur lsextern):

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

Verwenden von readarray(aka mapfile) in Bash 4:

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

Vielen Dank an gniourf_gniourf für die Vorschläge.


Dies kümmert sich nicht um Dateien mit Leerzeichen im Namen. Versuchen Sie Folgendes: dir = / tmp / testdir; rm -rf $ dir && mkdir $ dir && cd / $ dir && touch "Dies ist eine Datei" this_is_another_file && ls -1 && files = ($ (ls -1)) && list = $ {files [@] /% / ,} && list = $ {list% *,} && echo $ list
dimir

1
@ Dimir: Viele der Antworten auf diese Frage leiden unter diesem Problem. Ich habe meine Antwort so bearbeitet, dass Dateinamen mit Tabulatoren oder Leerzeichen, jedoch keine Zeilenumbrüche berücksichtigt werden.
Bis auf weiteres angehalten.

Ihre Bash-Version leidet auch unter Pfadnamenerweiterungen. Um ein Array aus Zeilen zu erstellen, verwenden Sie bitte mapfile(Bash ≥4) als : mapfile -t files < <(ls -1). Keine Notwendigkeit, damit herumzuspielen IFS. Und es ist auch kürzer.
gniourf_gniourf

Und wenn Sie Ihr Array haben, können Sie IFSdie Felder verbinden : saveIFS=$IFS; IFS=,; list=${files[*]}; IFS=$saveIFS. Oder verwenden Sie eine andere Methode, wenn Sie ein Trennzeichen mit mehr als einem Zeichen möchten.
gniourf_gniourf

1
@gniourf_gniourf: Ich habe Ihre Vorschläge in meine Antwort aufgenommen. Vielen Dank.
Bis auf weiteres angehalten.

24

Ich finde das großartig

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

ORS ist das "Trennzeichen für Ausgabedatensätze", sodass Ihre Zeilen jetzt mit einem Komma verbunden werden.


6
Dies schließt das nachfolgende Trennzeichen nicht aus.
Derek Mahar

6
Dies ist besonders beeindruckend, da mehrteilige Datensatztrennzeichen (z. B. " OR ") verwendet werden
Mat Schaffer,

15

Die Kombination aus Einstellung IFSund Verwendung von "$*"kann tun, was Sie wollen. Ich verwende eine Subshell, damit ich das $ IFS dieser Shell nicht störe

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

Um die Ausgabe zu erfassen,

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

2
Haben Sie weitere Informationen zur Funktionsweise set? Sieht für mich ein bisschen nach Voodoo aus. Ein flacher Blick man setbrachte mir auch nicht viele Informationen ein.
Ehtesh Choudhury

3
Wenn Sie seteine Reihe von Argumenten, aber keine Optionen angeben, werden die Positionsparameter festgelegt ($ 1, $ 2, ...). --ist zum Schutz da, setfalls das erste Argument (oder in diesem Fall der Dateiname) mit einem Bindestrich beginnt. Siehe die Beschreibung der --Option in help set. Ich finde die Positionsparameter eine bequeme Möglichkeit, eine Liste von Dingen zu handhaben. Ich hätte dies auch mit einem Array implementieren können:output=$( files=(*); IFS=,; echo "${files[*]}" )
Glenn Jackman

Dies ist großartig, da keine zusätzlichen Programme ausgeführt werden müssen und mit Dateinamen gearbeitet wird, die Leerzeichen oder sogar Zeilenumbrüche enthalten.
Eric

1
@EhteshChoudhury Wie type setSie sagen werden , set is a shell builtin. Also, man setwird nicht helfen, wird aber help settun. Antwort: "- Weisen Sie den Positionsparametern alle verbleibenden Argumente zu."
Stéphane Gourichon

Nach einem set -- *. Wenn Sie die Erweiterung um *eine Ebene verzögern, erhalten Sie möglicherweise die richtige Ausgabe, ohne dass eine Sub-Shell erforderlich ist : IFS=',' eval echo '"$*"'. Das ändert natürlich die Positionsparameter.
Isaac


9

Das Rad nicht neu erfinden.

ls -m

Es macht genau das.


Das OP wollte ein Trennzeichen, sodass Sie zum Konvertieren der Kommas immer noch ein tr benötigen. Es fügt auch ein Leerzeichen nach den Kommas hinzu, dh Datei1, Datei2, Datei3
Rob

Verwenden Sie also ls -mund trentfernen Sie das Leerzeichen nach dem Komma, das Sie tun würdenls -m | tr -d ' '
Andy

2
Diese Verwendung von tr löscht Leerzeichen in Dateinamen. besser zu bedienensed 's/, /,/g
Glenn Jackman

7

nur schlagen

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

5
Etwas effizienter wäre es, "printf -v mystring"% s | "*" zu verwenden - das vermeidet eine Abzweigung für die $ ()
camh

Aber vor allem nicht das Schleppen |, @camh.
Christopher

1
Nun, nur bashund printf
gnu

@camh Funktioniert aber printf -vnur in Bash, während die vorgestellte Antwort auf vielen Shell-Typen funktioniert.
Isaac

@Christopher Ja, das wird das Trailing entfernen |, vorausgesetzt, beide Zeilen werden verwendet : printf -v mystring "%s|" * ; echo ${mystring%|}.
Isaac

7

Dieser Befehl ist für die PERL-Fans:

ls -1 | perl -l40pe0

Hier ist 40 der oktale ASCII-Code für den Raum.

-p verarbeitet zeilenweise und druckt

-l wird dafür sorgen, dass das nachfolgende \ n durch das von uns bereitgestellte ASCII-Zeichen ersetzt wird.

-e soll PERL informieren, dass wir die Befehlszeilenausführung durchführen.

0 bedeutet, dass tatsächlich kein Befehl ausgeführt werden muss.

perl -e0 ist dasselbe wie perl -e ''


6

Um mögliche Verwirrung bei Zeilenumbrüchen für tr zu vermeiden, können wir ls das Flag -b hinzufügen:

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

5

Es sieht so aus, als ob die Antworten bereits existieren.

Wenn Sie a, b, cformatieren möchten , verwenden Sie ls -m( Antwort von Tulains Córdova )

Oder wenn Sie a b cFormat möchten , verwenden Sie ls | xargs(vereinfachte Version von Chris Js Antwort )

Oder wenn Sie ein anderes Trennzeichen wie möchten |, verwenden Sie ls | paste -sd'|'(Anwendung der Antwort von Artem )


5

Zusätzlich zur Antwort von Majkinetor können Sie nachfolgend das nachfolgende Trennzeichen entfernen (da ich seine Antwort noch nicht einfach kommentieren kann):

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

Entfernen Sie einfach so viele nachfolgende Bytes, wie Ihr Trennzeichen zählt.

Ich mag diesen Ansatz, weil ich Trennzeichen mit mehreren Zeichen + andere Vorteile von awk:

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

BEARBEITEN

Wie Peter bemerkt hat, wird die negative Byteanzahl in der nativen MacOS-Version von head nicht unterstützt. Dies kann jedoch leicht behoben werden.

Installieren Sie zuerst coreutils. "Die GNU Core Utilities sind die grundlegenden Dienstprogramme zur Datei-, Shell- und Textmanipulation des GNU-Betriebssystems."

brew install coreutils

Befehle, die auch von MacOS bereitgestellt werden, werden mit dem Präfix "g" installiert. Zum Beispiel gls.

Sobald Sie dies getan haben, können Sie verwenden, gheadwas eine negative Byteanzahl hat, oder besser Alias ​​erstellen:

alias head="ghead"

Hinweis: Negative Bytezahlen werden nur bei bestimmten Versionen von head unterstützt, sodass dies beispielsweise bei Macos nicht funktioniert.
Peter

Vielen Dank für den Hinweis. Ich habe eine Problemumgehung für MacOS hinzugefügt.
Aleksander Stelmaczonek

4

Der sed Weg,

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

Hinweis :

Dies ist linear in seiner Komplexität und wird nur einmal ersetzt, nachdem alle Zeilen an den Musterraum von sed angehängt wurden.

@ AnandRajasekas Antwort und einige andere ähnliche Antworten, wie hier , sind O (n²), da sed jedes Mal ersetzen muss, wenn eine neue Zeile an den Musterraum angehängt wird.

Vergleichen,

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

Wenn Ihre Version von xargs das Flag -d unterstützt, sollte dies funktionieren

ls  | xargs -d, -L 1 echo

-d ist das Trennzeichen

Wenn Sie -d nicht haben, können Sie Folgendes versuchen

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

Mit dem ersten xargs können Sie Ihr Trennzeichen angeben, das in diesem Beispiel ein Komma ist.


3
-dGibt das Eingabetrennzeichen mit GNU xargs an, funktioniert also nicht. Das zweite Beispiel zeigt das gleiche Problem wie andere Lösungen eines Streubegrenzers am Ende.
Thor

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

Erläuterung:

-e- bezeichnet einen auszuführenden Befehl
:a- ist eine Bezeichnung
/$/N- definiert den Umfang der Übereinstimmung für die aktuelle und die (N) ext-Zeile
s/\n/\\n/;- ersetzt alle EOL durch \n
ta;- gehe zu Bezeichnung a, wenn die Übereinstimmung erfolgreich ist

Entnommen aus meinem Blog .


2

Sie können verwenden:

ls -1 | perl -pe 's/\n$/some_delimiter/'

Dies schließt das nachfolgende Trennzeichen nicht aus.
Derek Mahar

2

lsErzeugt eine Spaltenausgabe, wenn es an ein Rohr angeschlossen ist, sodass das -1redundant ist.

Hier ist eine weitere Perl-Antwort mit der integrierten joinFunktion, die kein abschließendes Trennzeichen hinterlässt:

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

Das Obskure -0777lässt Perl alle Eingaben lesen, bevor das Programm ausgeführt wird.

sed Alternative, die kein nachfolgendes Trennzeichen hinterlässt

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

0

lshat die Möglichkeit -m, die Ausgabe durch ", "ein Komma und ein Leerzeichen zu begrenzen .

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

Wenn Sie dieses Ergebnis weiterleiten tr, um entweder das Leerzeichen oder das Komma zu entfernen, können Sie das Ergebnis erneut weiterleiten tr, um das Trennzeichen zu ersetzen.

In meinem Beispiel ersetze ich das Trennzeichen ,durch das Trennzeichen;

Ersetzen Sie ihn ;durch ein beliebiges Zeichenbegrenzer, da tr nur das erste Zeichen in den Zeichenfolgen berücksichtigt, die Sie als Argumente übergeben.


0

Mit chomp können Sie mehrere Zeilen in einer Zeile zusammenführen:

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

Setzen Sie die Zeilenumbruchbedingung in die if-Anweisung. Dies kann ein Sonderzeichen oder ein beliebiges Trennzeichen sein.


0

Schnelle Perl-Version mit Trailing Slash Handling:

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

Erklären:

  • Perl -E: Perl mit unterstützten Funktionen ausführen (z. B. ...)
  • Sagen Sie: Drucken Sie mit einem Träger zurück
  • join ",", ARRAY_HERE: Verbinde ein Array mit ","
  • map {chomp; $ _} ROWS: Entfernen Sie aus jeder Zeile die Trägerrückgabe und geben Sie das Ergebnis zurück
  • <>: stdin, jede Zeile ist eine REIHE. In Verbindung mit einer Karte wird ein Array für jede REIHE erstellt
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.