Як об’єднати кілька рядків імен файлів в один із спеціальним роздільником?


441

Я хотів би об'єднати результат ls -1в один рядок і розмежувати його з усім, що я хочу.

Чи є якісь стандартні команди Linux, які я можу використовувати для цього?

Відповіді:


689

Подібний до першого варіанту, але він не відриває відмітника

ls -1 | paste -sd "," -

29
Як зауваження, версія, яку я спробував, вставляє потрібний аргумент "-" в кінці, щоб сказати, щоб він читав з STDIN. Наприклад, ls -1 | paste -s -d ":" - не впевнений, що це універсально для всіх версій пасти
— Енді Уайт

4
цей кращий, тому що він дозволяє порожній роздільник :)
— Юра Пурбеєв

2
Примітка pasteотримує -(стандартний ввід) за замовчуванням, принаймні на моєму paste (GNU coreutils) 8.22.
— fedorqui 'ТАК перестаньте шкодити'

1
я просто підтримав це, це так, і тепер він має такі самі голоси, як і вибрана відповідь. ЦЕ ВІДПОВІДЬ. немає кінцевого деліметра
— thebugfinder

1
Порожній роздільник можна вказати за допомогою "\0", так що paste -sd "\0" -працював для мене!
— Бред Паркс

379

EDIT : Просто " ls -m " Якщо ви хочете, щоб ваш роздільник був комою

Ах, сила і простота!

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

Змініть кому " , " на що завгодно. Зауважте, що сюди входить "кінцева кома"


46
+1, але більш досконала версія повинна по-різному поводитися \ n
— mouviciel

5
Якщо ім'я файлу містить \nв ньому, це також замінить це.
— кодифікація

3
@ShreevatsaR: він має на увазі не додавати слідів "," Я вірю. такls -1 | tr "\\n" "," | sed 's/\(.*\),/\1/'
— Кріс

7
@Chris: ваш sedміг бути трохи ефективнішим із символом кінцевого маркера:ls -1 | tr "\\n" "," | sed 's/,$//'; echo ''
— pieman72

2
Використання sedпісля trздається просто для видалення останнього символу видається необгрунтованим. Я йду зls -1 | tr '\n' ',' | head -c -1
— reddot

29

Це замінює останню кому новим рядком:

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(ака mapfile) у Bash 4:

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

Спасибі gniourf_gniourf за пропозиції.


Це не піклується про файли з білими пробілами в імені. Спробуйте це: dir = / tmp / testdir; rm -rf $ dir && mkdir $ dir && cd / $ dir && торкніться "це файл" this_is_another_file && ls -1 && files = ($ (ls -1)) && list = $ {files [@] /% / ,} && list = $ {list% *,} && echo $ list
— dimir

1
@dimir: Багато відповідей на це питання страждають від цієї проблеми. Я відредагував свою відповідь, щоб дозволити назви файлів із вкладками чи пробілами, але не новими рядками.
— Призупинено до подальшого повідомлення.

Ваша версія bash також страждає від розширення імені шляху. Щоб побудувати масив з рядків, будь ласка , розгляньте можливість використання mapfile(Bash) ≥4 як: mapfile -t files < <(ls -1). Не потрібно сваритися IFS. І це теж коротше.
— gniourf_gniourf

І коли у вас є масив, ви можете використовувати , IFSщоб приєднатися поля: saveIFS=$IFS; IFS=,; list=${files[*]}; IFS=$saveIFS. Або скористайтеся іншим методом, якщо ви хочете розділити з більш ніж одним символом.
— gniourf_gniourf

1
@gniourf_gniourf: Я включив ваші пропозиції у свою відповідь. Дякую.
— Призупинено до подальшого повідомлення.

24

Я думаю, що цей дивовижний

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

ORS - це "роздільник вихідних записів", тому тепер ваші рядки будуть з'єднані комою.


6
Це не виключає делімітера задніх знаків.
— Дерек Махар

6
Це особливо приголомшливо через обробку розділювачів записів із кількома символами (наприклад, " OR ")
— Mat Schaffer

15

Поєднання налаштування IFSта використання "$*"може робити все, що завгодно. Я використовую нижню оболонку, тому я не заважаю $ IFS цієї оболонки

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

Щоб захопити вихід,

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

2
У вас є ще якась інформація про те, як setпрацює? На мене це трохи схоже на вуду. неглибокий погляд через man setмене також не приніс багато інформації.
— Ehtesh Choudhury

3
Якщо ви даєте setкупу аргументів, але немає варіантів, він встановлює позиційні параметри ($ 1, $ 2, ...). --чи є захист setу випадку, якщо перший аргумент (або ім'я файлу в цьому випадку) починається з тире. Дивіться опис --параметра в help set. Я знаходжу позиційні параметри зручним способом обробки списку речей. Я також міг реалізувати це за допомогою масиву:output=$( files=(*); IFS=,; echo "${files[*]}" )
— glenn jackman

Це чудово, оскільки не потребує виконання будь-яких додаткових програм, і він працює з іменами файлів, що містять пробіли або навіть нові рядки.
— Ерік

1
@EhteshChoudhury Як type setскаже вам, що set is a shell builtin. Отже, man setне допоможе, але help setзробить. Відповідь: "- Призначте будь-які інші аргументи позиційним параметрам."
— Стефан Гурішон

Після а set -- *. Відстрочка розширення *одного рівня ви можете отримати правильний висновок без необхідності підпроекту оболонки: IFS=',' eval echo '"$*"'. Звичайно, це змінить позиційні параметри.
— Ісаак

13

lsЗагальний аналіз не рекомендується , тому альтернативним кращим способом є використання find, наприклад:

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

Або за допомогою findта paste:

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

Для загального приєднання до декількох рядків (не пов'язаних з файловою системою), перевірте: Короткий та портативний "приєднання" в командному рядку Unix .


9

Не винаходити колесо.

ls -m

Це робить саме це.


ОП хотів отримати будь-який роздільник, тому вам все одно знадобиться tr для перетворення коми. Він також додає пробіл після коми, тобто file1, file2, file3
— відключити

тож використовуючи ls -mта trвидаляючи пробіл після коми, яку ви зробитеls -m | tr -d ' '
— Енді

2
що використання tr видалить пробіли всередині імен файлів. краще використовуватиsed 's/, /,/g
— glenn jackman

7

просто баш

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

5
Трохи ефективнішим буде використання "printf -v mystring"% s | "*" - що дозволяє уникнути вилки за $ ()
— camh

Але помітно не |чіпляє слідів, @camh.
— Крістофер

1
Ну просто bashі гну coreutilsprintf
— ThorSummoner

@camh Але printf -vбуде працювати лише в bash, тоді як представлена ​​відповідь працює на багатьох типах оболонок.
— Ісаак

@Christopher Так, це призведе до видалення завершального |, при умови , що використовуються обидва ліній: printf -v mystring "%s|" * ; echo ${mystring%|}.
— Ісаак

7

Ця команда призначена для шанувальників PERL:

ls -1 | perl -l40pe0

Тут 40 - осьовий код ассії для простору.

-p буде обробляти рядок за рядком та друкувати

- я подбаю про заміну останнього \ n символом ascii, який ми надаємо.

-е, щоб повідомити PERL, що ми виконуємо виконання командного рядка.

0 означає, що фактично немає команди для виконання.

perl -e0 те саме, що perl -e ''


6

Щоб уникнути потенційної плутанини нового рядка для tr, ми можемо додати прапор -b до ls:

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

5

Схоже, відповіді вже є.

Якщо ви хочете a, b, cформату, використовуйте ls -m(відповідь Тулана Кордова )

Або якщо ви хочете a b cформату, використовуйте ls | xargs(спрощена версія відповіді Кріса Дж )

Або якщо ви хочете мати будь-який інший роздільник |, використовуйте ls | paste -sd'|'(застосування відповіді Артема )


5

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

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

Просто видаліть стільки кінцевих байтів, скільки розраховується ваш роздільник.

Мені подобається такий підхід, оскільки я можу використовувати розділові знаки з кількома символами + інші переваги awk:

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

EDIT

Як зауважив Петро, ​​у рідній версії MacOS не підтримується від'ємне число байтів. Однак це можна легко виправити.

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

brew install coreutils

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

Після цього ви можете скористатись gheadнегативним числом байтів, а ще краще зробити псевдонім:

alias head="ghead"

Примітка: від'ємне число байтів підтримується лише у певних версіях заголовка, тому це не працюватиме, наприклад, у macos.
— Пітер

Дякую, що вказали на це. Я додав рішення для MacOS.
— Олександр Стельмачонек

4

Сед шлях,

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

Примітка :

Це лінійно за складністю, замінюючи лише один раз після того, як всі рядки додаються до простору Шаблону sed.

@ AnandRajaseka в відповідь , і деякі інші подібні відповіді, такі , як тут , є O (n²), тому що СЕД повинна робити замінити кожен раз , коли новий рядок додається в шаблон простору.

Порівнювати,

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

Якщо ви версія xargs підтримує прапор -d, це має працювати

ls  | xargs -d, -L 1 echo

-d - прапор роздільника

Якщо у вас немає -d, ви можете спробувати наступне

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

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


3
-dвказує роздільник введення з xargs GNU, тому не буде працювати. Другий приклад демонструє те саме питання, що й інші рішення тут збитого роздільника в кінці.
— Тор

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

lsвидає один вихід стовпця при підключенні до труби, тому -1надлишок.

Ось ще одна відповідь perl за допомогою вбудованої joinфункції, яка не залишає делімітера в кінці:

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

Незрозуміле -0777змушує перл прочитати всі входи перед запуском програми.

sed альтернатива, яка не залишає кінцевого роздільника

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

0

lsмає можливість -mрозмежувати висновок ", "комою та пробілом.

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

трубопровід цього результату, щоб trвидалити пробіл, або кома дозволить вам знову передати результат, trщоб замінити роздільник.

у моєму прикладі я замінюю роздільник ,на роздільник;

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


0

Ви можете використовувати chomp для об'єднання декількох рядків в один рядок:

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

введіть умову перерви рядка в операторі if. Це може бути спеціальний символ або будь-який роздільник.


0

Швидка версія Perl з обробкою косою рисою:

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

Пояснити:

  • perl -E: виконати Perl з підтримкою функцій (скажімо, ...)
  • скажіть: друк із зворотним носієм
  • приєднатися ",", ARRAY_HERE: приєднатися до масиву з ","
  • карта {chomp; $ _} ROWS: видаліть з кожного рядка повернення оператора і поверніть результат
  • <>: stdin, кожен рядок є ROW, з'єднання з картою створить масив кожного ROW
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.