Я хотел бы изменить порядок строк в текстовом файле (или стандартный ввод), сохранив содержимое каждой строки.
Итак, т.е. начиная с:
foo
bar
baz
Я хотел бы закончить с
baz
bar
foo
Для этого есть стандартная утилита командной строки UNIX?
Я хотел бы изменить порядок строк в текстовом файле (или стандартный ввод), сохранив содержимое каждой строки.
Итак, т.е. начиная с:
foo
bar
baz
Я хотел бы закончить с
baz
bar
foo
Для этого есть стандартная утилита командной строки UNIX?
Ответы:
Также стоит упомянуть: tac
(Гм, реверс cat
). Часть coreutils .
tac a.txt > b.txt
brew install coreutils
(устанавливается gtac
по умолчанию).
echo -n "abc\ndee" > test; tac test
,
Есть известные уловки sed :
# 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
и TAC.
tac
ожидается, что он будет обрабатывать произвольные большие файлы, которые не помещаются в памяти (хотя длина строки все еще ограничена). Неясно, sed
работает ли решение для таких файлов.
в конце вашей команды поставьте:
| 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
Мне действительно нравится ответ " tail -r ", но мой любимый ответ gawk - ....
gawk '{ L[n++] = $0 }
END { while(n--)
print L[n] }' file
mawk
на Ubuntu 14.04 LTS - работает, поэтому оно не является специфичным для GNU awk. +1
n++
можно заменить наNR
РЕДАКТИРОВАТЬ следующее генерирует случайным образом отсортированный список чисел от 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
внутри сценария оболочки, используйте homebrew, как уже упоминалось выше, тогда просто псевдоним 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
$
На основании ответа от ephemient , который сделал почти, но не совсем то, что я хотел.
Со мной случается, что я хочу получить последние 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, который является строкой 1m0
.%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 editor 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 <>'
но, вероятно, это применимо и к другим методам).