реферат
Друкуйте рядки без нового рядка, додайте новий рядок лише в тому випадку, якщо є ще один рядок для друку.
$ printf 'one\ntwo\n' |
awk '{ printf( "%s%s" , NR>1?"\n":"" , $0 ) }'; echo " done"
one
two done
Інші рішення
Якщо ми працювали з файлом, ми можемо просто обрізати з нього один символ (якщо він закінчується на новому рядку):
removeTrailNewline () {[[$ (хвіст -c 1 "$ 1")]] || обрізати -s-1 "$ 1"; }
Це швидке рішення, оскільки йому потрібно прочитати з файлу лише один символ, а потім видалити його безпосередньо ( truncate
), не читаючи весь файл.
Однак, працюючи з даними з stdin (потоку), дані повинні бути прочитані, і всі вони. І, вона "споживається", як тільки її читають. Немає зворотних треків (як у врізання). Щоб знайти кінець потоку, нам потрібно прочитати до кінця потоку. У цей момент немає можливості повернутися назад на вхідний потік, дані вже "спожиті". Це означає, що дані повинні зберігатися в якійсь формі буфера, поки ми не узгодимо кінець потоку, а потім зробимо щось із даними в буфері.
Найбільш очевидне рішення - перетворити потік у файл та обробити цей файл. Але питання задає якийсь фільтр потоку. Не про використання додаткових файлів.
змінна
Наївним рішенням було б захопити весь вхід у змінну:
FilterOne(){ filecontents=$(cat; echo "x"); # capture the whole input
filecontents=${filecontents%x}; # Remove the "x" added above.
nl=$'\n'; # use a variable for newline.
printf '%s' "${filecontents%"$nl"}"; # Remove newline (if it exists).
}
printf 'one\ntwo' | FilterOne ; echo 1done
printf 'one\ntwo\n' | FilterOne ; echo 2done
printf 'one\ntwo\n\n' | FilterOne ; echo 3done
пам'ять
Можна завантажити цілий файл в пам'ять за допомогою sed. У sed неможливо уникнути останнього рядка на останньому рядку. GNU sed може уникнути друку останнього рядка, але тільки якщо у вихідному файлі його вже немає. Отже, ні, простий сед не може допомогти.
За винятком GNU awk з -z
опцією:
sed -z 's/\(.*\)\n$/\1/'
За допомогою awk (будь-якого awk) промацуйте весь потік, і printf
це без зворотного рядка.
awk ' { content = content $0 RS }
END { gsub( "\n$", "", content ); printf( "%s", content ) }
'
Завантаження цілого файлу в пам’ять може бути не дуже хорошою ідеєю, це може зайняти багато пам'яті.
Два рядки в пам'яті
У дивовижному режимі ми можемо обробити два рядки в циклі, зберігаючи попередній рядок у змінній та роздрукувавши даний:
awk 'NR>1{print previous} {previous=$0} END {printf("%s",$0)}'
Пряма обробка
Але ми могли б зробити краще.
Якщо ми друкуємо теперішній рядок без нового рядка і друкуємо новий рядок лише тоді, коли існує наступний рядок, ми обробляємо по одному рядку і останній рядок не матиме наступного нового рядка:
awk 'NR == 1 {printf ("% s", $ 0); далі}; {printf ("\ n% s", $ 0)} '
Або написано іншим способом:
awk 'NR>1{ print "" }; { printf( "%s", $0 ) }'
Або:
awk '{ printf( "%s%s" , NR>1?"\n":"" , $0 ) }'
Тому:
$ printf 'one\ntwo\n' | awk '{ printf( "%s%s" , NR>1?"\n":"" , $0 ) }'; echo " done"
one
two done
chomp
, оскількиchomp
видаляє лише максимум один зворотний новий рядок.