unix - trabalhando - utilizando o sed no linux




Como posso extrair um intervalo predeterminado de linhas de um arquivo de texto no Unix? (15)

Bastante simples usando cabeça / cauda:

head -16482 in.sql | tail -258 > out.sql

usando sed:

sed -n '16482,16482p' in.sql > out.sql

usando o awk:

awk 'NR>=10&&NR<=20' in.sql > out.sql

Eu tenho um despejo de SQL de linha ~ 23000 contendo vários bancos de dados no valor de dados. Eu preciso extrair uma determinada seção deste arquivo (ou seja, os dados para um único banco de dados) e colocá-lo em um novo arquivo. Conheço os números de linha inicial e final dos dados que desejo.

Alguém sabe um comando Unix (ou uma série de comandos) para extrair todas as linhas de um arquivo entre as linhas 16224 e 16482 e depois redirecioná-las para um novo arquivo?


Como estamos falando de extrair linhas de texto de um arquivo de texto, darei um caso especial em que você deseja extrair todas as linhas que correspondam a um determinado padrão.

myfile content:
=====================
line1 not needed
line2 also discarded
[Data]
first data line
second data line
=====================
sed -n '/Data/,$p' myfile

Vai imprimir a linha [Dados] e o restante. Se você quiser que o texto da linha 1 ao padrão, digite: sed -n '1, / Data / p' myfile. Além disso, se você conhecer dois padrões (melhor ser exclusivo em seu texto), tanto a linha inicial como a final do intervalo poderão ser especificadas com correspondências.

sed -n '/BEGIN_MARK/,/END_MARK/p' myfile

Eu acho que isso pode ser uma solução útil. Se o nome da tabela for "pessoa", você poderá usar sed para obter todas as linhas necessárias para restaurar sua tabela.

sed -n -e '/DROP TABLE IF EXISTS.*`person `/,/UNLOCK TABLES/p' data.sql  > new_data.sql

Com base nesta resposta , onde está faltando o "DROP TABLE IF EXIST" para a tabela que você está restaurando e você precisa excluir algumas linhas da parte inferior do novo arquivo antes de usá-lo para evitar a exclusão da próxima tabela.

Informações detalhadas também podem ser encontradas here


Eu escrevi um pequeno script bash que você pode executar a partir de sua linha de comando, desde que você atualize seu PATH para incluir seu diretório (ou você pode colocá-lo em um diretório que já esteja contido no PATH).

Uso: $ pinch filename end-line end-line

#!/bin/bash
# Display line number ranges of a file to the terminal.
# Usage: $ pinch filename start-line end-line
# By Evan J. Coon

FILENAME=$1
START=$2
END=$3

ERROR="[PINCH ERROR]"

# Check that the number of arguments is 3
if [ $# -lt 3 ]; then
    echo "$ERROR Need three arguments: Filename Start-line End-line"
    exit 1
fi

# Check that the file exists.
if [ ! -f "$FILENAME" ]; then
    echo -e "$ERROR File does not exist. \n\t$FILENAME"
    exit 1
fi

# Check that start-line is not greater than end-line
if [ "$START" -gt "$END" ]; then
    echo -e "$ERROR Start line is greater than End line."
    exit 1
fi

# Check that start-line is positive.
if [ "$START" -lt 0 ]; then
    echo -e "$ERROR Start line is less than 0."
    exit 1
fi

# Check that end-line is positive.
if [ "$END" -lt 0 ]; then
    echo -e "$ERROR End line is less than 0."
    exit 1
fi

NUMOFLINES=$(wc -l < "$FILENAME")

# Check that end-line is not greater than the number of lines in the file.
if [ "$END" -gt "$NUMOFLINES" ]; then
    echo -e "$ERROR End line is greater than number of lines in file."
    exit 1
fi

# The distance from the end of the file to end-line
ENDDIFF=$(( NUMOFLINES - END ))

# For larger files, this will run more quickly. If the distance from the
# end of the file to the end-line is less than the distance from the
# start of the file to the start-line, then start pinching from the
# bottom as opposed to the top.
if [ "$START" -lt "$ENDDIFF" ]; then
    < "$FILENAME" head -n $END | tail -n +$START
else
    < "$FILENAME" tail -n +$START | head -n $(( END-START+1 ))
fi

# Success
exit 0

Eu estava prestes a postar o truque de cabeça / cauda, ​​mas na verdade eu provavelmente apenas acionaria o emacs. ;-)

  1. esc - x goto-line ret 16224
  2. marca ( ctrl - espaço )
  3. esc - x goto-line ret 16482
  4. esc - w

abra o novo arquivo de saída, ctl-y save

Me deixe ver o que está acontecendo.


Eu queria fazer a mesma coisa de um script usando uma variável e consegui-lo colocando aspas ao redor da variável $ para separar o nome da variável do p:

sed -n "$first","$count"p imagelist.txt >"$imageblock"

Eu queria dividir uma lista em pastas separadas, encontrei a pergunta inicial e respondi uma etapa útil. (comando split não é uma opção no sistema operacional antigo que eu tenho que portar código para).


Existe outra abordagem com o awk :

awk 'NR==16224, NR==16482' file

Se o arquivo for grande, pode ser bom exit depois de ler a última linha desejada. Desta forma, não lerá desnecessariamente o arquivo até o final:

awk 'NR==16224, NR==16482-1; NR==16482 {print; exit}' file

Isso pode funcionar para você (GNU sed):

sed -ne '16224,16482w newfile' -e '16482q' file

ou aproveitando o bash:

sed -n $'16224,16482w newfile\n16482q' file

O -n nas respostas aceitas funciona. Aqui está outra maneira no caso de você estar inclinado.

cat $filename | sed "${linenum}p;d";

Isso faz o seguinte:

  1. canalizar o conteúdo de um arquivo (ou inserir o texto como quiser).
  2. sed seleciona a linha dada, imprime
  3. d é necessário para excluir linhas, caso contrário, o sed assumirá que todas as linhas serão eventualmente impressas. ou seja, sem o d, você terá todas as linhas impressas pela linha selecionada impressas duas vezes porque você tem a parte $ {linenum} p pedindo para que seja impressa. Tenho certeza que o -n está basicamente fazendo a mesma coisa que o d aqui.

Rapido e sujo:

head -16428 < file.in | tail -259 > file.out

Provavelmente não é a melhor maneira de fazer isso, mas deve funcionar.

BTW: 259 = 16482-16224 + 1.


Você poderia usar 'vi' e, em seguida, o seguinte comando:

:16224,16482w!/tmp/some-file

Alternativamente:

cat file | head -n 16482 | tail -n 258

EDIT: - Apenas para adicionar uma explicação, você usa head -n 16482 para exibir as primeiras 16482 linhas e depois usar tail -n 258 para obter as últimas 258 linhas da primeira saída.


sed -n '16224,16482p' < dump.sql


cat dump.txt | head -16224 | tail -258

deve fazer o truque. A desvantagem dessa abordagem é que você precisa fazer a aritmética para determinar o argumento da cauda e explicar se você quer que o 'entre' inclua a linha final ou não.


perl -ne 'print if 16224..16482' file.txt > new_file.txt

sed -n '16224,16482p;16483q' filename > newfile

Do manual do sed :

p - Imprime o espaço do padrão (para a saída padrão). Esse comando geralmente é usado apenas em conjunto com a opção de linha de comando -n.

n - Se a impressão automática não estiver desativada, imprima o espaço de padrão e, de qualquer forma, substitua o espaço de padrão pela próxima linha de entrada. Se não houver mais entrada, o sed sai sem processar mais comandos.

q - Saia do sed sem processar mais comandos ou entrada. Observe que o espaço de padrão atual é impresso se a impressão automática não estiver desativada com a opção -n.

and

Endereços em um script sed podem estar em qualquer um dos seguintes formatos:

number A especificação de um número de linha corresponderá apenas àquela linha na entrada.

Um intervalo de endereços pode ser especificado especificando dois endereços separados por uma vírgula (,). Um intervalo de endereços corresponde a linhas a partir de onde o primeiro endereço corresponde e continua até que o segundo endereço corresponda (inclusive).





text-processing