GNU/Linux >> Linux Esercitazione >  >> Linux

Come spostare una riga in un file di testo su o giù di una riga?

Ho alcuni file di testo e vorrei poter spostare una riga arbitraria in uno qualsiasi dei file in alto o in basso di una riga (le righe all'inizio o alla fine del file rimarrebbero dove si trovano). Ho del codice funzionante ma sembra ingannevole e non sono convinto di aver coperto tutti i casi limite, quindi mi chiedo se c'è qualche strumento o paradigma che lo fa meglio (ad esempio, più facile da capire il codice (per altri lettori o me in 6 mesi), più facile da eseguire il debug e più facile da mantenere; "più efficiente" non è molto importante).

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
}

Posso eseguire il controllo degli errori degli input all'interno o all'esterno di queste funzioni, ma i punti bonus se l'input errato (come numeri interi, file inesistenti o numeri di riga maggiori della lunghezza del file) viene gestito in modo sano.

Voglio che venga eseguito in uno script Bash sui moderni sistemi Debian/Ubuntu. Non ho sempre l'accesso come root, ma posso aspettarmi che vengano installati strumenti "standard" (pensa a un server Web condiviso) e potrei essere in grado di richiedere l'installazione di altri strumenti se posso giustificare la richiesta (sebbene meno dipendenze esterne è sempre meglio).

Esempio:

$ 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
$ 

Risposta accettata:

Simile a Archemar 's suggerimento, potresti scriverlo con ed :

printf %s\n ${linenr}m${addr} w q | ed -s infile

cioè

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

per esempio. per spostare la linea n. 21 una formazione:

printf %s\n 21m19 w q | ed -s infile

per spostare la linea n. 21 una riga in basso:

printf %s\n 21m22 w q | ed -s infile

Ma poiché devi solo spostare una determinata riga su o giù di una riga, potresti anche dire che vuoi praticamente scambiare due righe consecutive. Incontra sed :

sed -i -n 'addr{h;n;G};p' infile

cioè

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

per esempio. per spostare la linea n. 21 una formazione:

sed -i -n '20{h;n;G};p' infile

per spostare la linea n. 21 una riga in basso:

sed -i -n '21{h;n;G};p' infile

Ho usato gnu sed sintassi sopra. Se la portabilità è un problema:

sed -n 'addr{
h
n
G
}
p' infile

A parte questo, i soliti controlli:il file esiste ed è scrivibile; file_length > 2; line_no. > 1; line_no. < file_length;


Linux
  1. Come inserire del testo prima della prima riga di un file?

  2. Come trovare parentesi non corrispondenti in un file di testo?

  3. Come analizzare ogni riga di un file di testo come argomento di un comando?

  4. Come aggiungere riga di intestazione e trailer a un file in Linux

  5. Come posso elencare un nome file per riga di output in Linux?

Come spostare un file in Linux

Come leggere i file riga per riga in Bash

Come leggere un file riga per riga in Bash

Come spostarsi verso il basso di una directory?

Come toccare un file e mkdir se necessario in una riga

Come inserisco il testo nella prima riga di un file usando sed?