파일의 줄 순서를 바꾸려면 어떻게해야합니까?
각 줄의 내용을 유지하면서 텍스트 파일 (또는 stdin)의 줄 순서를 바꾸고 싶습니다.
즉, 다음으로 시작합니다.
foo
bar
baz
나는 끝내고 싶다.
baz
bar
foo
이를위한 표준 UNIX 명령 줄 유틸리티가 있습니까?
BSD 꼬리 :
tail -r myfile.txt
참조 : FreeBSD , NetBSD , OpenBSD 및 OS 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)
tac
Linux에서 작동하는을 시도 하고 작동하지 않으면 tail -r
BSD 및 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:
- Read from stdin
- For each line move it to line 1 (to reverse). Command is
g/^/m0
. This means globally, for each lineg
; match the start of the line, which matches anything^
; move it after address 0, which is line 1m0
. - Print everything. Command is
%p
. This means for the range of all lines%
; print the linep
. - Forcefully quit without saving the file. Command is
q!
. This means quitq
; 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
'IT박스' 카테고리의 다른 글
jQuery로 HTML 문자열 이스케이프 (0) | 2020.10.03 |
---|---|
cURL을 사용하여 요청 및 응답 시간을 한 번에 측정하려면 어떻게합니까? (0) | 2020.10.03 |
Java에서 객체의 크기를 결정하는 가장 좋은 방법은 무엇입니까? (0) | 2020.10.03 |
"u"및 "r"문자열 플래그는 정확히 무엇을하며 원시 문자열 리터럴은 무엇입니까? (0) | 2020.10.03 |
다양한 커밋을 선택하고 다른 브랜치에 병합하는 방법은 무엇입니까? (0) | 2020.10.03 |