问题
I am trying to swap the first line with last line in a text file in unix file has:
line1
line2
line3
line4
line5
line6
I want like this:
line6
line2
line3
line4
line5
line1
I am using sed -n -e '1 s/^.*$/$p' file
. Which is not happening.
回答1:
EDIT2: As per Ed sir's comment adding this solution too here which will be more suitable in case 2nd line is empty then also it will work.
awk 'NR==1{first=$0;next} NR>2{val=val prev ORS} {prev=$0} END{print prev ORS val first} Input_file
EDIT: To exchange only first and last line following may help you(considering that your Input_file is same as shown sample).
awk 'FNR==1{first=$0;next} {val=(val?val ORS prev:prev?$0:"")} {prev=$0} END{print $0 ORS val ORS first}' Input_file
Explanation:
awk '
FNR==1{ ##Checking if line is first line then do following.
first=$0; ##Creating varable first whose value is current line value.
next ##next will skip all further statements from here.
}
{
val=(val?val ORS prev:prev?$0:"") ##Creating variable named val here whoe value is concatenating to its own value with variable prev value.
}
{
prev=$0 ##Creating variable prev whose value will be current value of line but will become previous value for next line.
}
END{
print $0 ORS val ORS first ##Printing current line ORS val ORS and first here.
}' Input_file ##Mentioning Input_file name here.
Could you please try following and let me know if this helps you.
awk -v from=1 -v to=6 'FNR==from{source=$0;next} FNR==to{target=$0;next} {val=val?val ORS $0:$0} END{print target ORS val ORS source}' Input_file
回答2:
This might work for you (GNU sed):
sed 'H;$!d;x;s/\n\([^\n]*\)\(\n.*\n\)\(.*\)/\3\2\1/' file
Copy the whole file into the hold space (HS) and after the last line, swap to the HS, split the file into first line, middle and last line and substitute the first and last lines.
A two pass alternative solution:
sed -n '1s/.*/$c&/p;$s/.*/1c&/p' file | sed -f - file
Create a sed script to change the first line to the last and last line to the first.
Another solution using cat, head, tail and sed:
cat <(tail -1 file) <(sed '1d;$d' file) <(head -1 file)
Another sed solution:
sed -E '1h;1d;:a;N;$!ba;s/(.*)\n(.*)/\2\n\1/;G' file
回答3:
In sed, you'll need to make two passes; it probably makes more sense to use ed instead. Then we just need two move commands - move the last line to just after line 1, then move the first line to the end:
$m1
1m$
Demo
#!/bin/bash
set -euo pipefail
# Create our input file
file=$(mktemp)
trap 'rm "$file"' EXIT
cat >"$file" <<END
line1
line2
line3
line4
line5
line6
END
echo Before:
cat "$file"
echo
# Make the change
ed -s "$file" <<<$'$m1\n1m$\nwq'
# Show the result
echo After:
cat "$file"
If you need to write a different output file, you can of course add a filename argument to the wq
command, as usual.
回答4:
Just in case a oneliner mixing, head
, tail
and sed
:
$ FIRST=$(head -1 file.txt) LAST=$(tail -1 file.txt) \
sed "1 s/^.*$/${LAST}/" file.txt | sed "$ s/^.*$/${FIRST}/"
回答5:
For very large files, you might be interested in a double pass:
awk '(NR!=FNR){print (FNR==1 ? t : (FNR==c ? h : $0) ); next }
(NR==1){h=$0}{t=$0;c=NR}' file file
回答6:
Using the sponge util:
f=file
{ tail -1 $f ; tail -n +2 $f | head -n -1 ; head -1 $f ; } | sponge $f
来源:https://stackoverflow.com/questions/51440378/how-to-swap-the-first-line-with-last-line-in-a-text-file-using-sed-awk