IT박스

파일의 줄 순서를 바꾸려면 어떻게해야합니까?

itboxs 2020. 10. 3. 10:13
반응형

파일의 줄 순서를 바꾸려면 어떻게해야합니까?


각 줄의 내용을 유지하면서 텍스트 파일 (또는 stdin)의 줄 순서를 바꾸고 싶습니다.

즉, 다음으로 시작합니다.

foo
bar
baz

나는 끝내고 싶다.

baz
bar
foo

이를위한 표준 UNIX 명령 줄 유틸리티가 있습니까?


BSD 꼬리 :

tail -r myfile.txt

참조 : FreeBSD , NetBSD , OpenBSDOS X 매뉴얼 페이지.


또한 언급 할 가치가 있습니다 : tac(the, ahem, reverse of cat). coreutils일부 입니다.

한 파일을 다른 파일로 뒤집기

tac a.txt > b.txt

있다 잘 알려진 나오지 트릭 :

# 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 one-liners에서 (빠른 실행으로) 또는 :

awk '{a[i++]=$0} END {for (j=i-1; j>=0;) print a[j--] }' file*

기억이 안나시면

perl -e 'print reverse <>'

GNU 유틸리티가있는 시스템에서 다른 답은 더 간단하지만 모든 것이 GNU / 리눅스 인 것은 아닙니다 ...


당신은에 될 일 경우 vim사용

:g/^/m0

$ (tac 2> /dev/null || tail -r)

tacLinux에서 작동하는을 시도 하고 작동하지 않으면 tail -rBSD 및 OSX에서 작동하는을 사용하십시오 .


tac <file_name>

예:

$ cat file1.txt
1
2
3
4
5

$ tac file1.txt
5
4
3
2
1

명령 끝에 다음을 입력하십시오. | tac

tac은 당신이 요구하는 것을 정확히 수행합니다. "각 파일을 표준 출력으로, 마지막 줄을 먼저 기록합니다."

tac은 cat :-)의 반대입니다.


다음 명령을 시도하십시오.

grep -n "" myfile.txt | sort -r -n | gawk -F : "{ print $2 }"

Just Bash :) (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

가장 간단한 방법은 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

다음을 편집 하면 1에서 10까지 무작위로 정렬 된 숫자 목록이 생성됩니다.

seq 1 10 | sort -R | tee /tmp/lst |cat <(cat /tmp/lst) <(echo '-------') **...**

where dots are replaced with actual command which reverses the list

tac

seq 1 10 | sort -R | tee /tmp/lst |cat <(cat /tmp/lst) <(echo '-------') \
<(tac)

python: using [::-1] on 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]))")

For cross OS (i.e. OSX, Linux) solution that may use tac inside a shell script use homebrew as others have mentioned above, then just alias tac like so:

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

This will work on both BSD and GNU.

awk '{arr[i++]=$0} END {while (i>0) print arr[--i] }' filename

If you want to modify the file in place, you can run

sed -i '1!G;h;$!d' filename

This removes the need to create a temporary file and then delete or rename the original and has the same result. For example:

$tac file > file2
$sed -i '1!G;h;$!d' file
$diff file file2
$

Based on the the answer by ephemient, which did almost, but not quite, what I wanted.


Best solution:

tail -n20 file.txt | tac

For Emacs users: C-x h (select the whole file) and then M-x reverse-region. Also works for only selecting parts or the lines and reverting those.


I see lots of interesting ideas. But try my idea. Pipe your text into this:

rev | tr '\n' '~' | rev | tr '~' '\n'

which assumes that the character '~' is not in the file. This should work on every UNIX shell going back to 1961. Or something like that.


I had the same question, but I also wanted the first line (header) to stay on top. So I needed to use the power of 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 also works in cygwin or gitbash


You can do it with vim stdin and stdout. You can also use ex to be POSIX compliant. vim is just the visual mode for ex. In fact, you can use ex with vim -e or vim -E (improved ex mode). vim is useful because unlike tools like sed it buffers the file for editing, while sed is used for streams. You might be able to use awk, but you would have to manually buffer everything in a variable.

The idea is to do the following:

  1. Read from stdin
  2. For each line move it to line 1 (to reverse). Command is g/^/m0. This means globally, for each line g; match the start of the line, which matches anything ^; move it after address 0, which is line 1 m0.
  3. Print everything. Command is %p. This means for the range of all lines %; print the line p.
  4. Forcefully quit without saving the file. Command is q!. This means quit q; forcefully !.
# 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

How to make this reusable

I use a script I call ved (vim editor like sed) to use vim to edit stdin. Add this to a file called ved in your path:

#!/usr/bin/env sh

vim - --not-a-term -Es "$@" +'%p | q!'

I am using one + command instead of +'%p' +'q!', because vim limits you to 10 commands. So merging them allows the "$@" to have 9 + commands instead of 8.

Then you can do:

seq 10 | ved +'g/^/m0'

If you don't have vim 8, put this in ved instead:

#!/usr/bin/env sh

vim -E "$@" +'%p | q!' /dev/stdin

tail -r works in most Linux and MacOS systems

seq 1 20 | tail -r


sort -r < filename

or

rev < filename

참고URL : https://stackoverflow.com/questions/742466/how-can-i-reverse-the-order-of-lines-in-a-file

반응형