Я хотів би змінити порядок рядків у текстовому файлі (або 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 <>'але це, ймовірно, стосується і інших методів).