Как я могу изменить порядок строк в файле?

417

Я хотел бы изменить порядок строк в текстовом файле (или stdin), сохраняя содержимое каждой строки.

Итак, то есть, начиная с:

foo
bar
baz

Я хочу закончить с

baz
bar
foo

Существует ли для этого стандартная утилита командной строки UNIX?

  • 2
    Важное примечание об изменении строк: сначала убедитесь, что в вашем файле есть завершающий символ новой строки . В противном случае две последние строки входного файла будут объединены в одну строку выходного файла (по крайней мере, с помощью perl -e 'print reverse <>' но, вероятно, это применимо и к другим методам).
  • 0
    Возможный дубликат Как перевернуть строки текстового файла?
Показать ещё 1 комментарий
Теги:
command-line

15 ответов

316
Лучший ответ

BSD tail:

tail -r myfile.txt

Ссылка: FreeBSD, NetBSD, OpenBSD и OS X страницы руководства.

  • 101
    Просто помните, что опция -r не совместима с POSIX. Приведенные ниже решения sed и awk будут работать даже в самых сложных системах.
  • 0
    (если есть Perl в этой системе Winky, то есть :))
Показать ещё 15 комментариев
1103

Также стоит упомянуть: tac (the, ahem, reverse от cat). Часть coreutils.

Переключение одного файла на другой

tac a.txt > b.txt
  • 66
    Особенно стоит упомянуть тех, кто использует версию tail без опции -r! (У большинства пользователей Linux есть хвост GNU, у которого нет -r, поэтому у нас есть GNU tac).
  • 10
    Просто примечание, потому что люди уже упоминали tac ранее, но tac, похоже, не установлен на OS X. Не то чтобы было сложно написать замену в Perl, но у меня нет реальной.
Показать ещё 10 комментариев
114

Там известные 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...

  • 4
    Из того же источника: awk '{a [i ++] = $ 0} END {for (j = i-1; j> = 0;) напечатать файл [j--]}' * Обе версии sed и awk работают над мой маршрутизатор busybox. 'tac' и 'tail -r' этого не делают.
  • 8
    Я желаю, чтобы это был принятый ответ. coz sed всегда доступен, но не tail -r и tac.
Показать ещё 4 комментария
48

Если вы оказались в vim, используйте

:g/^/m0
  • 5
    Связанный: Как изменить порядок строк? на Vim SE
  • 1
    Я бы проголосовал, если бы вы кратко объяснили, что он сделал.
Показать ещё 3 комментария
37
$ (tac 2> /dev/null || tail -r)

Попробуйте tac, который работает в Linux, и если это не сработает, используйте tail -r, который работает на BSD и OSX.

  • 4
    Почему бы не tac myfile.txt - что мне не хватает?
  • 8
    @sage, вернуться к tail -r если tac недоступен. tac не соответствует POSIX. Ни один не tail -r . Все еще не надежно, но это повышает шансы на то, что все работает.
Показать ещё 5 комментариев
21

Попробуйте выполнить следующую команду:

grep -n "" myfile.txt | sort -r -n | gawk -F : "{ print $2 }"
  • 0
    вместо выражения gawk я бы сделал что-то вроде этого: sed 's/^[0-9]*://g'
  • 2
    почему бы не использовать "nl" вместо grep -n?
Показать ещё 3 комментария
14

Просто Bash:) (4.0 +)

function print_reversed {
    readarray -t LINES
    for (( I = ${#LINES[@]}; I; )); do
        printf '%s\n' "${LINES[--I]}"
    done
}

print_reversed < file
  • 1
    +1 за ответ в bash и за O (n) и за неиспользование рекурсии (+3, если бы я мог)
  • 1
    Попробуйте это с файлом, содержащим строку -nenenenenenene и -nenenenenenene причину, по которой люди рекомендуют всегда использовать printf '%s\n' вместо echo .
Показать ещё 1 комментарий
11

Самый простой способ - использовать команду 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 
  • 1
    Я не уверен, почему этот ответ появляется перед тем, как показано ниже, но это всего лишь пачка stackoverflow.com/a/742485/1174784, которая была опубликована много лет назад.
10
tac <file_name>

Пример:

$ cat file1.txt
1
2
3
4
5

$ tac file1.txt
5
4
3
2
1
10

Мне очень нравится ответ "tail -r", но мой любимый ответ gawk -....

gawk '{ L[n++] = $0 } 
  END { while(n--) 
        print L[n] }' file
  • 1
    это GNU awk конкретно?
  • 0
    Протестировано с mawk на Ubuntu 14.04 LTS - работает, поэтому это не специфично для GNU awk. +1
2

Для решения перекрестных ОС (например, OSX, Linux), которые могут использовать tac внутри оболочки script, используйте homebrew, как упоминалось выше, а затем просто псевдоним tac, например:

brew install coreutils
echo "alias tac='gtac'" >> ~/.bash_aliases (or wherever you load aliases)
source ~/.bash_aliases
tac myfile.txt
2

Лучшее решение:

tail -n20 file.txt | tac
  • 0
    Добро пожаловать в переполнение стека! Хотя этот фрагмент кода может решить вопрос, в том числе объяснение действительно помогает улучшить качество вашего сообщения. Помните, что вы отвечаете на вопрос читателей в будущем, и эти люди могут не знать причин, по которым вы предлагаете код. Также постарайтесь не переполнять ваш код пояснительными комментариями, это снижает удобочитаемость кода и пояснений!
2

ИЗМЕНИТЬ следующее генерирует беспорядочно отсортированный список чисел от 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]))")
0

У меня был тот же вопрос, но я также хотел, чтобы первая строка (заголовок) оставалась на вершине. Поэтому мне нужно было использовать мощность 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

  • 0
    Это приводит к 1\n20\n19...2\n а не к 20\n19...\2\n1\n .
-5
sort -r < filename

или

rev < filename
  • 5
    sort -r работает, только если входные данные уже отсортированы, что здесь не так. rev переворачивает символы в строке, но сохраняет порядок строк, что тоже не то, о чем просил Скотти. Так что этот ответ на самом деле не является ответом вообще.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню