Saya memiliki beberapa file teks, dan saya ingin dapat memindahkan garis arbitrer di salah satu file ke atas atau ke bawah satu baris (baris di awal atau akhir file akan tetap berada di tempatnya). Saya memiliki beberapa kode yang berfungsi tetapi tampaknya kludgy dan saya tidak yakin saya memiliki semua kasus Edge yang tercakup, jadi saya bertanya-tanya apakah ada beberapa alat atau paradigma yang melakukan ini dengan lebih baik (mis. saya dalam 6 bulan), lebih mudah di-debug, dan lebih mudah dirawat; “lebih efisien” tidak terlalu penting).
move_up() {
# fetch line with head -<line number> | tail -1
# insert that one line higher
# delete the old line
sed -i -e "$((line_number-1))i$(head -$line_number $file | tail -1)" -e "${line_number}d" "$file"
}
move_down() {
file_length=$(wc -l < "$file")
if [[ "$line_number" -ge $((file_length - 1)) ]]; then
# sed can't insert past the end of the file, so append the line
# then delete the old line
echo $(head -$line_number "$file" | tail -1) >> "$file"
sed -i "${line_number}d" "$file"
else
# get the line, and insert it after the next line, and delete the original
sed -i -e "$((line_number+2))i$(head -$line_number $file | tail -1)" -e "${line_number}d" "$file"
fi
}
Saya dapat melakukan pemeriksaan kesalahan input di dalam atau di luar fungsi ini, tetapi poin bonus jika input yang buruk (seperti non-bilangan bulat, file yang tidak ada, atau nomor baris yang lebih besar dari panjang file) ditangani dengan baik.
Saya ingin itu berjalan dalam skrip Bash pada sistem Debian/Ubuntu modern. Saya tidak selalu memiliki akses root tetapi dapat mengharapkan alat "standar" untuk diinstal (pikirkan server web bersama), dan mungkin dapat meminta pemasangan alat lain jika saya dapat membenarkan permintaan tersebut (meskipun lebih sedikit ketergantungan eksternal selalu lebih baik).
Contoh:
$ cat b
1
2
3
4
$ file=b line_number=3 move_up
$ cat b
1
3
2
4
$ file=b line_number=3 move_down
$ cat b
1
3
4
2
$
Jawaban yang Diterima:
Mirip dengan Archemar Sarannya, Anda dapat membuat skrip ini dengan ed
:
printf %s\n ${linenr}m${addr} w q | ed -s infile
yaitu
linenr # is the line number
m # command that moves the line
addr=$(( linenr + 1 )) # if you move the line down
addr=$(( linenr - 2 )) # if you move the line up
w # write changes to file
q # quit editor
misalnya untuk pindah baris no. 21
satu baris:
printf %s\n 21m19 w q | ed -s infile
untuk pindah baris no. 21
satu baris ke bawah:
printf %s\n 21m22 w q | ed -s infile
Tetapi karena Anda hanya perlu memindahkan baris tertentu ke atas atau ke bawah satu baris, Anda juga bisa mengatakan bahwa Anda praktis ingin menukar dua baris berturut-turut. Temui sed
:
sed -i -n 'addr{h;n;G};p' infile
yaitu
addr=${linenr} # if you move the line down
addr=$(( linenr - 1 )) # if you move the line up
h # replace content of the hold buffer with a copy of the pattern space
n # read a new line replacing the current line in the pattern space
G # append the content of the hold buffer to the pattern space
p # print the entire pattern space
misalnya untuk pindah baris no. 21
satu baris:
sed -i -n '20{h;n;G};p' infile
untuk pindah baris no. 21
satu baris ke bawah:
sed -i -n '21{h;n;G};p' infile
Saya menggunakan gnu sed
sintaks di atas. Jika portabilitas menjadi perhatian:
sed -n 'addr{
h
n
G
}
p' infile
Selain itu, pemeriksaan biasa:file ada dan dapat ditulis; file_length > 2
; line_no. > 1
; line_no. < file_length
;