Обробка тексту - з'єднуйте кожні два рядки комами


35

У мене є більше 1000 рядків у файлі. Файл починається наступним чином (додаються номери рядків):

Station Name
Station Code
A N DEV NAGAR
ACND
ABHAIPUR
AHA
ABOHAR
ABS
ABU ROAD
ABR

Мені потрібно конвертувати це у файл із записами, розділеними комами, шляхом з'єднання кожні два рядки. Кінцеві дані повинні виглядати так

Station Name,Station Code
A N DEV NAGAR,ACND
ABHAIPUR,AHA
ABOHAR,ABS
ABU ROAD,ABR
...

Я намагався - спробувати написати сценарій оболонки, а потім echoїх із комою між ними. Але я здогадуюсь, що простіший ефективний однокласник зробив би цю роботу, можливо, в sed/ awk.

Якісь ідеї?


@ l0b0 Ви відредагували зауваження ОП, що номери рядків "є лише для пояснення" ...
Jasonwryan

@jasonwryan Вибачте, я подумав, що рядки є для пояснення. Помилка розбору в рядку 0.
l0b0

Відповіді:


39

Просто використовуйте cat(якщо вам подобаються коти ;-)) та paste:

cat file.in | paste -d, - - > file.out

Пояснення: pasteчитає з декількох файлів і вставляє разом відповідні рядки (рядок 1 з першого файлу з рядком 1 з другого файлу тощо):

paste file1 file2 ...

Замість імені файлу ми можемо використовувати -(тире). pasteбере перший рядок з file1 (що є stdin). Потім він хоче прочитати перший рядок з file2 (що також stdin). Однак, оскільки перший рядок stdin вже був прочитаний та оброблений, то тепер на вхідному потоці чекає другий рядок stdin, який pasteщасливо склеюється з першим. Цей -dпараметр встановлює роздільник як кома, а не вкладка.

Крім того, зробіть

cat file.in | sed "N;s/\n/,/" > file.out

PS Так, можна спростити вищесказане

< file.in sed "N;s/\n/,/" > file.out

або

< file.in paste -d, - - > file.out

що має перевагу не використовувати cat.

Тим НЕ менше, я не використовував цю ідіому навмисне , для наочності - це менш багатослівним , і я , як cat(Котам NICE). Тому, будь ласка, не редагуйте.

Крім того, якщо ви віддаєте перевагу вставці котам (paste - це команда об'єднувати файли по горизонталі, а кішка об'єднує їх вертикально), ви можете використовувати:

paste file.in | paste -d, - -

Просто ще раз про це. Номери рядків не є частиною файлу :)
mtk

paste Команда відмінно працює, будь ласка , ви можете дати трохи більше пояснень по цього приводу. Дефіси ???
mtk

2
Дефіси означають "читати зі стдин". Якщо одне і те ж джерело вхідного сигналу повторюється, paste знає читати з нього кілька разів на рядок виводу.
сумнівним

@sch: класна редакція, я її не торкаюся :-)
січня

1
Стосовно вашого catаргументу. Хто sed "N;s/\n/,/" file.in > file.outне працює?
Бернхард

8

У випадку, якщо хтось, хто тут приземлився, хоче об'єднати всі лінії в один лайнер CSV, спробуйте

cat file | tr '\n' ','

3
sed 'N;s/\n/,/' file

Використовуючи sed, з'єднайте (N) кожні 2 рядки та замініть новий рядок (\ n) на ",".


3
paste -sd ',\n' file.in > file.out

Також зауважте, що оскільки ми просто замінюємо один символ на інший (кожен інший новий рядок комою), ми можемо працювати над вхідним файлом на місці:

paste -sd ',\n' file.in 1<> file.in

(але будьте обережні, це може не працювати в системах, що не мають Unix, які мають термінали CRLF (наприклад, Microsoft), які деякі емульовані POSIX pasteможуть обробляти не-Unix способом)


Що 1це робить тут 1<>? це помилка друку?
αғsnιη

@ αғsnιη, дивіться це
iruvar

@iruvar дякую
αғsnιη

2

Ось однолінійний (хоча потенційно мільйони команд запустіть-er) за допомогою чистого Bash:

(IFS=; while read -r name; do read -r code; printf '%s\n" "$name,$code"; done < file.in) > file.out

Я використовую нижню оболонку (парантез), щоб мені не довелося зберігати та відновлювати IFS. Що інакше слід зробити, щоб не зіпсувати середовище користувачів, якщо джерело знайдеться. Альтернативою було б передати , що нові IFS тільки readяк в IFS= read -r name, IFS= read -r code.

Той факт, що всі команди в циклі вбудовані в оболонку, робить її ефективність прийнятною і навіть швидшою, ніж інші рішення для невеликих файлів. Але багато людей вважають це поганою практикою, і слід бути обережними, узагальнюючи її до чого-небудь іншого.


загалом, так, щоб використовувати підрозділи для локалізації змін середовища. Але в цьому випадку це не потрібно: замість цього можна робити while IFS='\n' read -r name; do IFS='\n' read -r code ... done < file.in, що є ідіомою, яку я часто бачу в скриптах оболонки. -rПрапор readозначає «інтерпретувати символ" \ " , за якою слід символ" п "в потоці стандартного введення в вигляді двох символів, а не як символ нового рядка.» Можливо, може бути більш естетичним створення нижньої оболонки, як ви робите, ніж повторення IFS='\n'.
сумнівним

@dubiousjim: -rтехнічно покращене рішення. Чудово! Я не прихильник ідеї пройти змінену IFSдвічі. Якби я використав одне читання, дуже приємно, але не двічі. Звичайно, це питання думки . Використання нижньої оболонки трохи перевищує загальні знання Баша, я б сказав, тому у багатьох людей виникнуть проблеми з розумінням її мети. Це погано.
Видалено

2

Для повного набору відповідей можливим awkрішенням може бути:

awk 'NR%2==1 {printf $0","} NR%2==0 { print $0}' *file*

@downvoter: Що не так у моїй відповіді, щоб заслужити скорочення? Як її можна вдосконалити?
Бернхард

Може тому, що ледачий printf? Не вдасться у рідкісному випадку, коли назва станції містить специфікатор формату. (Див. Для прикладу pastebin.com/wgxFttrJ .) Але це лише здогадка, знищення не від мене.
манатура

1

Хриплий старий каштан awkідіоми

awk '{ORS=NR%2?",":"\n";print}' file
Station Name,Station Code
A N DEV NAGAR,ACND
ABHAIPUR,AHA
ABOHAR,ABS
ABU ROAD,ABR

awk '{ORS=NR%2?",":"\n"};1'коротше і більше ідіоми
cuonglm

@cuonglm, я сумніваюся. У цьому випадку це все-таки однорівнева лінія, незважаючи на те, printі намір зрозумілий. 1такий же чіткий для старих awkрук, як я, але я вважаю за кращеprint
iruvar

Це було перше просте рішення, яке я виявив, що його легко налаштувати на більш ніж 2 рядки. Я sedпевний час боровся з пошуком, але awkполегшував поєднання кожні 4 рядки. Врятував мене поїздку до $EDITOR!
opello


0

Наприклад:

seq 0 70 | xargs -L 2 | sed 's/ /,/g'

Вихід: (Примітка: xargs -L number_of_columnsчудово працює з більшістю будь-якої кількості стовпців, а не кожні два рядки)

0,1
2,3
4,5
6,7
8,9
10,11
12,13
14,15
16,17
18,19
20,21
22,23
24,25
26,27
28,29
30,31
32,33
34,35
36,37
38,39
40,41
42,43
44,45
46,47
48,49
50,51
52,53
54,55
56,57
58,59
60,61
62,63
64,65
66,67
68,69
70

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.