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


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.