Я хотів би змінити порядок рядків у текстовому файлі (або stdin), зберігаючи вміст кожного рядка.
Отже, тобто починаючи з:
foo
bar
baz
Я хотів би закінчити
baz
bar
foo
Чи існує для цього стандартна утиліта командного рядка UNIX?
Я хотів би змінити порядок рядків у текстовому файлі (або stdin), зберігаючи вміст кожного рядка.
Отже, тобто починаючи з:
foo
bar
baz
Я хотів би закінчити
baz
bar
foo
Чи існує для цього стандартна утиліта командного рядка UNIX?
Відповіді:
Також варто згадати: tac
(the, ahem, revers of cat
). Частина Coreutils .
tac a.txt > b.txt
brew install coreutils
(встановлюється gtac
за замовчуванням).
echo -n "abc\ndee" > test; tac test
.
Є відомі трюки :
# reverse order of lines (emulates "tac")
# bug/feature in HHsed v1.5 causes blank lines to be deleted
sed '1!G;h;$!d' # method 1
sed -n '1!G;h;$p' # method 2
(Пояснення: додайте непочатковий рядок для зберігання буфера, рядка підкачки та буфера утримування, виведення рядка в кінці)
Як варіант (із швидшим виконанням) з однокласників awk :
awk '{a[i++]=$0} END {for (j=i-1; j>=0;) print a[j--] }' file*
Якщо ви цього не можете згадати,
perl -e 'print reverse <>'
У системі з утилітами GNU інші відповіді простіші, але не весь світ GNU / Linux ...
tail -r
таc.
tac
очікується, що обробляє довільні великі файли, які не вміщуються в пам'яті (хоча довжина рядка все ще обмежена). Незрозуміло, чи sed
працює рішення для таких файлів.
наприкінці вашої команди поставте:
| tac
tac робить саме те, що ви просите, це "Запишіть кожен ФАЙЛ до стандартного виводу, останній рядок спочатку".
tac - це протилежність коту :-).
tac
команди. Це корисно для нових користувачів, які можуть шукати ту саму тему.
Якщо ви випадково vim
використовуєтесь
:g/^/m0
$ (tac 2> /dev/null || tail -r)
Спробуйте tac
, що працює на Linux, а якщо це не працює tail -r
, то це працює на BSD та OSX.
tac myfile.txt
- чого мені не вистачає?
tail -r
випадку, якщо tac
це недоступно. tac
не сумісний з POSIX. Ні tail -r
. Досі не є надійною, але це покращує шанси на роботу.
tac
вона доступна, але вичерпано оперативну пам’ять і поміняється наполовину через споживання гігантського вхідного потоку. Він виходить з ладу, а потім tail -r
вдається обробити залишок потоку, даючи неправильний результат.
brew install coreutils
і використовувати gtac
замість цього, tac
і якщо ви віддаєте перевагу додавати tac як псевдонім, gtac
якщо, наприклад, ви хотіли сценарію оболонки, який використовував його крос-платформу (Linux, OSX)
Спробуйте виконати таку команду:
grep -n "" myfile.txt | sort -r -n | gawk -F : "{ print $2 }"
sed 's/^[0-9]*://g'
nl
за замовчуванням не вдасться пронумерувати порожні рядки. Ця -ba
опція доступна в деяких системах, не є універсальною (HP / UX приходить в голову, хоча я б хотів, щоб це не було), тоді як grep -n
завжди буде нумеруватися кожен рядок, що відповідає (у цьому випадку порожнім) регулярним виразом.
cut -d: -f2-
Просто Баш :) (4.0+)
function print_reversed {
local lines i
readarray -t lines
for (( i = ${#lines[@]}; i--; )); do
printf '%s\n' "${lines[i]}"
done
}
print_reversed < file
-nenenenenenene
і засвідчіть причину, чому люди рекомендують завжди використовувати printf '%s\n'
замість цього echo
.
Найпростіший метод - використання tac
команди. tac
є cat
зворотним. Приклад:
$ cat order.txt
roger shah
armin van buuren
fpga vhdl arduino c++ java gridgain
$ tac order.txt > inverted_file.txt
$ cat inverted_file.txt
fpga vhdl arduino c++ java gridgain
armin van buuren
roger shah
Мені дуже подобається відповідь " хвіст-р ", але моя улюблена відповідь гоук - це ....
gawk '{ L[n++] = $0 }
END { while(n--)
print L[n] }' file
mawk
на Ubuntu 14.04 LTS - працює, тому це не є специфічним для GNU awk. +1
n++
можна замінити наNR
EDIT, наступне створює випадково відсортований список чисел від 1 до 10:
seq 1 10 | sort -R | tee /tmp/lst |cat <(cat /tmp/lst) <(echo '-------') **...**
де точки замінюються фактичною командою, яка перевертає список
так
seq 1 10 | sort -R | tee /tmp/lst |cat <(cat /tmp/lst) <(echo '-------') \
<(tac)
python: використовуючи [:: - 1] на sys.stdin
seq 1 10 | sort -R | tee /tmp/lst |cat <(cat /tmp/lst) <(echo '-------') \
<(python -c "import sys; print(''.join(([line for line in sys.stdin])[::-1]))")
Для крос-операційної системи (тобто для OSX, Linux), яка може використовувати tac
сценарій оболонки, використовуйте домашню мову, як згадували інші, тоді просто псевдонім так:
Встановіть lib
Для MacOS
brew install coreutils
Для Linux debian
sudo apt-get update
sudo apt-get install coreutils
Потім додайте псевдонім
echo "alias tac='gtac'" >> ~/.bash_aliases (or wherever you load aliases)
source ~/.bash_aliases
tac myfile.txt
Якщо ви хочете змінити файл на місці, можете запустити
sed -i '1!G;h;$!d' filename
Це усуває необхідність створити тимчасовий файл, а потім видалити або перейменувати оригінал і мати такий же результат. Наприклад:
$tac file > file2
$sed -i '1!G;h;$!d' file
$diff file file2
$
Спираючись на відповідь ефемієнта , яка зробила майже, але не зовсім те, чого я хотів.
Це відбувається зі мною , що я хочу , щоб отримати останні n
рядки дуже великий текстовий файл ефективно .
Перше , що я спробував це tail -n 10000000 file.txt > ans.txt
, але я знайшов , що це дуже повільно, бо tail
повинен прагнути до місця , а потім переміщається назад , щоб роздрукувати результати.
Коли я розумію це, я переключаюсь на інше рішення: tac file.txt | head -n 10000000 > ans.txt
. Цього разу позицію пошуку потрібно просто перемістити з кінця в потрібне місце, і це економить 50% часу !
Прийняти домашнє повідомлення:
Використовуйте, tac file.txt | head -n n
якщо у вас tail
немає -r
можливості.
Найкраще рішення:
tail -n20 file.txt | tac
Для користувачів Emacs: C-x h
(виберіть весь файл), а потім M-x reverse-region
. Також працює лише для вибору частин або ліній та їх повернення.
У мене було те саме питання, але я також хотів, щоб перший рядок (заголовок) залишився вгорі. Тому мені потрібно було використовувати силу awk
cat dax-weekly.csv | awk '1 { last = NR; line[last] = $0; } END { print line[1]; for (i = last; i > 1; i--) { print line[i]; } }'
PS також працює в cygwin або gitbash
1\n20\n19...2\n
а не до 20\n19...\2\n1\n
.
Ви можете це зробити за допомогою vim
stdin
і stdout
. Ви також ex
можете бути сумісними з POSIX . vim
це лише візуальний режим для ex
. Насправді, ви можете використовувати ex
з ( vim -e
або vim -E
вдосконалений ex
режим).
vim
корисна тим, що на відміну від таких інструментів, як sed
він буферизує файл для редагування, в той час як sed
він використовується для потоків. Ви можете використовуватиawk
, але вам доведеться вручну зберігати все в змінній.
Ідея полягає в тому, щоб зробити наступне:
g/^/m0
. Це означає глобально, для кожного рядка g
; відповідати початку рядка, що відповідає чому-небудь ^
; перемістіть його за адресою 0, яка є рядком 1 m0
.%p
. Це означає для діапазону всіх ліній %
; роздрукувати рядок p
.q!
. Це означає кинути q
; насильно !
.# Generate a newline delimited sequence of 1 to 10
$ seq 10
1
2
3
4
5
6
7
8
9
10
# Use - to read from stdin.
# vim has a delay and annoying 'Vim: Reading from stdin...' output
# if you use - to read from stdin. Use --not-a-term to hide output.
# --not-a-term requires vim 8.0.1308 (Nov 2017)
# Use -E for improved ex mode. -e would work here too since I'm not
# using any improved ex mode features.
# each of the commands I explained above are specified with a + sign
# and are run sequentially.
$ seq 10 | vim - --not-a-term -Es +'g/^/m0' +'%p' +'q!'
10
9
8
7
6
5
4
3
2
1
# non improved ex mode works here too, -e.
$ seq 10 | vim - --not-a-term -es +'g/^/m0' +'%p' +'q!'
# If you don't have --not-a-term, use /dev/stdin
seq 10 | vim -E +'g/^/m0' +'%p' +'q!' /dev/stdin
# POSIX compliant (maybe)
# POSIX compliant ex doesn't allow using + sign to specify commands.
# It also might not allow running multiple commands sequentially.
# The docs say "Implementations may support more than a single -c"
# If yours does support multiple -c
$ seq 10 | ex -c "execute -c 'g/^/m0' -c '%p' -c 'q!' /dev/stdin
# If not, you can chain them with the bar, |. This is same as shell
# piping. It's more like shell semi-colon, ;.
# The g command consumes the |, so you can use execute to prevent that.
# Not sure if execute and | is POSIX compliant.
seq 10 | ex -c "execute 'g/^/m0' | %p | q!" /dev/stdin
Як зробити це для багаторазового використання
Я використовую скрипт, який я викликаю ved
(редактор Vim, як sed
), щоб використовувати vim для редагування stdin
. Додайте це до файлу, який називається ved
на вашому шляху:
#!/usr/bin/env sh
vim - --not-a-term -Es "$@" +'%p | q!'
Я використовую одну +
команду замість +'%p' +'q!'
, тому що vim обмежує вас на 10 команд. Тож об'єднання їх дозволяє "$@"
мати 9+
команд замість 8.
Тоді ви можете зробити:
seq 10 | ved +'g/^/m0'
Якщо у вас немає vim 8, замініть це ved
:
#!/usr/bin/env sh
vim -E "$@" +'%p | q!' /dev/stdin
rev
text here
або
rev <file>
або
rev texthere
sort -r < filename
або
rev < filename
sort -r
працює лише якщо вхід вже відсортований, що тут не так. rev
обертає символи на рядок, але зберігає порядковий порядок недоторканим, що також не те, про що Скотті просив. Тож ця відповідь насправді взагалі не відповідає.
perl -e 'print reverse <>'
але це, ймовірно, стосується і інших методів).