Как объединить несколько строк с именами файлов в одну с пользовательским разделителем?

351

Я хотел бы присоединиться к результату ls -1 в одну строку и разделить его на все, что захочу.

Существуют ли какие-либо стандартные команды Linux, которые я могу использовать для этого?

Теги:
merge
parsing

19 ответов

524
Лучший ответ

Аналогично самой первой опции, но опускает конечный разделитель

ls -1 | paste -sd "," -
  • 27
    Как примечание, версия вставки, которую я пробовал, требует в конце аргумента "-", чтобы указать, что он должен читать из STDIN. например, ls -1 | paste -s -d ":" - Не уверен, что это универсально со всеми версиями paste
  • 3
    этот лучше, потому что он позволяет пустой разделитель :)
Показать ещё 5 комментариев
338

EDIT: просто " ls -m". Если вы хотите, чтобы ваш разделитель был запятой

Ah, сила и простота!

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

Измените запятую "," на все, что вы хотите. Обратите внимание, что это включает в себя "конечную запятую"

  • 42
    +1, но более сложная версия должна обрабатывать последний \ n по-другому
  • 5
    Если имя файла содержит \n , это также заменит его.
Показать ещё 10 комментариев
18

Это заменяет последнюю запятую на новую строку:

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

ls -m включает символы новой строки на символе ширины экрана (например, 80-е).

В основном Bash (только ls является внешним):

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

Используя readarray (aka mapfile) в Bash 4:

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

Благодаря gniourf_gniourf для предложений.

  • 0
    Это не позаботится о файлах с пробелами в имени. Попробуйте это: dir = / tmp / testdir; rm -rf $ dir && mkdir $ dir && cd / $ dir && touch "это файл" this_is_another_file && ls -1 && files = ($ (ls -1)) && list = $ {files [@] /% / ,} && list = $ {list% *,} && echo $ list
  • 1
    @dimir: Многие из ответов на этот вопрос страдают от этой проблемы. Я отредактировал свой ответ, чтобы разрешить имена файлов с табуляцией или пробелами, но не переводы строк.
Показать ещё 6 комментариев
17

Я думаю, что это потрясающе

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

ORS является "разделителем выходных записей", поэтому теперь ваши строки будут соединяться запятой.

  • 5
    Это не исключает конечный разделитель.
  • 3
    Это особенно здорово из-за обработки многосимвольных разделителей записей (например, " OR " )
14

Комбинация установки IFS и использования "$*" может делать то, что вы хотите. Я использую подоболочку, поэтому я не вмешиваюсь в эту оболочку $IFS

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

Чтобы записать вывод,

output=$(set -- *; IFS=,; echo "$*")
  • 2
    У вас есть еще информация о том, как работает set ? Для меня это выглядит как вуду. поверхностный взгляд на man set не принес мне много информации.
  • 3
    Если вы задаете set аргументов, но не имеете опций, он устанавливает позиционные параметры ($ 1, $ 2, ...). -- есть ли для защиты set в случае, если первый аргумент (или имя файла в этом случае) начинается с тире. Смотрите описание опции -- в help set . Я считаю позиционные параметры удобным способом обработки списка вещей. Я мог бы также реализовать это с помощью массива: output=$( files=(*); IFS=,; echo "${files[*]}" )
Показать ещё 3 комментария
12

Разбор ls вообще не рекомендуется, поэтому альтернативным вариантом является использование find, например:

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

Или используя find и paste:

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

Для общего объединения нескольких строк (не связанных с файловой системой), проверьте: Краткий и переносимый "join" в командной строке Unix.

9

Не изобретайте велосипед.

ls -m

Он делает именно это.

  • 0
    ОП требовал любой разделитель, поэтому вам все равно понадобится tr для преобразования запятых. Он также добавляет пробел после запятых, т.е. файл1, файл2, файл3
  • 0
    поэтому, используя ls -m и tr для удаления пробела после запятой, вы должны выполнить ls -m | tr -d ' '
Показать ещё 1 комментарий
7

Эта команда предназначена для вентиляторов PERL:

ls -1 | perl -l40pe0

Здесь 40 - восьмеричный код ascii для пространства.

-p будет обрабатываться по строкам и печатать

-l позаботится о замене конечного \n символом ascii, который мы предоставляем.

-e - сообщить PERL, что мы выполняем выполнение командной строки.

0 означает, что на самом деле нет команды для выполнения.

perl -e0 такой же, как perl -e ''

  • 11
    Мои глаза........
  • 2
    «Сжатие gzip не ухудшает читабельность Perl». :)
7

только bash

mystring=$(printf "%s|" *)
echo ${mystring%|}
  • 5
    Чуть более эффективным было бы использовать "printf -v mystring"% s | "*" - чтобы избежать форка для $ ()
  • 0
    Но, в частности, не разбивает трейлинг | @camh.
Показать ещё 5 комментариев
6

Чтобы избежать возможной путаницы новой строки для tr, мы могли бы добавить флаг -b в ls:

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

Похоже, ответы уже существуют.

Если вы хотите a, b, c, используйте ls -m (ответ Tulains Córdovas)

Или, если вы хотите формат a b c, используйте ls | xargs (упрощенная версия Chris Js answer)

Или, если вы хотите любой другой разделитель, например |, используйте ls | paste -sd'|' (приложение Артемов ответ)

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

Пояснение:

-e - обозначает команду для запуска
 :a - это метка  /$/N - определяет область соответствия для текущей и (N) строки ext  s/\n/\\n/; - заменяет все EOL на \n
 ta; - goto label a, если матч успешный

Взято из мой блог.

2

Седь,

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 the last line ($) do not (!) jump to (b) label :a (a) - break loop
  # s/\n/,/g   # any substitution you want

Замечания:

Это линейный по сложности, заменяющий только один раз после добавления всех строк в шаблонное пространство sed.

Ответ @AnandRajaseka и некоторые другие подобные ответы, такие как здесь, являются O (n²), потому что sed должен делать замену каждый раз, когда новая строка добавляется в Пространство Образца.

Сравнивать,

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
2

ls выводит один вывод столбца при подключении к трубе, поэтому -1 является избыточным.

Вот еще один ответ perl, используя встроенную функцию join, которая не оставляет трейлинг-разделителя:

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

Неясное -0777 заставляет perl читать все входные данные перед запуском программы.

sed альтернатива, которая не оставляет трейлинг-разделителя

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

Вы можете использовать:

ls -1 | perl -pe 's/\n$/some_delimiter/'
  • 0
    Почему знак $?
  • 0
    Это не исключает конечный разделитель.
2

Если версия xargs поддерживает флаг -d, тогда это должно работать

ls  | xargs -d, -L 1 echo

-d - флаг разделителя

Если у вас нет -d, вы можете попробовать следующее

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

Первые xargs позволяют указать ваш разделитель, который является запятой в этом примере.

  • 2
    -d указывает входной разделитель с помощью GNU xargs, поэтому не будет работать. Второй пример демонстрирует ту же проблему, что и другие решения здесь, в отношении случайного разделителя в конце.
1

Добавляя поверх ответа majkinetor, вот способ удаления конечного разделителя (поскольку я пока не могу просто комментировать его ответ):

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

Просто удалите столько конечных байтов, сколько рассчитывает ваш разделитель.

Мне нравится этот подход, потому что я могу использовать многосимвольные разделители + другие преимущества awk:

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

РЕДАКТИРОВАТЬ

Как заметил Питер, отрицательный счетчик байтов не поддерживается в родной версии головы MacOS. Это, однако, может быть легко исправлено.

Сначала установите coreutils. "Основные утилиты GNU - это базовые утилиты для работы с файлами, оболочками и текстом в операционной системе GNU".

brew install coreutils

Команды, также предоставляемые MacOS, устанавливаются с префиксом "g". Например, gls.

Как только вы это сделаете, вы можете использовать, ghead с отрицательным числом байтов или лучше, сделать псевдоним:

alias head="ghead"
  • 0
    Примечание: отрицательное число байтов поддерживается только в определенных версиях head, поэтому это не сработает, например, в macos.
  • 0
    Спасибо что подметил это. Я добавил обходной путь для MacOS.
0

Вы можете использовать chomp для объединения нескольких строк в одну строку:

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

положить условие прерывания строки в if statement.It может быть особым символом или любым разделителем.

0

ls имеет опцию -m, чтобы разграничить вывод с помощью ", " запятой и пробелом.

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

для этого результата до tr для удаления пробела или запятой вы можете снова передать результат на tr, чтобы заменить разделитель.

в моем примере я заменяю разделитель , разделителем ;

заменить ; на любой один разделитель символов, который вам больше нравится, поскольку tr только учетные записи для первого символа в строках, которые вы передаете в качестве аргументов.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню