Question

J'ai un cliché SQL d'environ 23 000 lignes contenant plusieurs bases de données. J'ai besoin d'extraire une certaine section de ce fichier (c'est-à-dire les données d'une seule base de données) et de la placer dans un nouveau fichier. Je connais les numéros de ligne de début et de fin des données que je souhaite.

Quelqu'un connaît-il une commande Unix (ou une série de commandes) permettant d'extraire toutes les lignes d'un fichier compris entre la ligne 16224 et 16482, puis de les rediriger vers un nouveau fichier?

Était-ce utile?

La solution

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

Extrait du manuel sed :

  

p -       Imprimez l'espace du modèle (sur la sortie standard). Cette commande est généralement utilisée uniquement avec l'option de ligne de commande -n.

     

n -       Si l'impression automatique n'est pas désactivée, imprimez l'espace du motif, puis remplacez-le malgré tout par la ligne suivante. Si   il n'y a pas plus d'entrée puis sed sort sans traitement plus   commandes.

     

q -   Quittez sed sans traiter plus de commandes ni d’entrée.   Notez que l’espace motif actuel est imprimé si l’impression automatique n’est pas désactivée avec l’option -n.

et

  

Les adresses d'un script sed peuvent revêtir l'une des formes suivantes:

     

nombre       Spécifier un numéro de ligne ne correspond qu'à cette ligne dans l'entrée.

     

Une plage d'adresses peut être spécifiée en spécifiant deux adresses.   séparés par une virgule (,). Une plage d'adresses correspond aux lignes à partir de   où la première adresse correspond, et continue jusqu'à la deuxième   correspondances d'adresse (inclusivement).

Autres conseils

sed -n '16224,16482 p' orig-data-file > new-file

Où 16224,16482 sont le numéro de la ligne de début et le numéro de la ligne de fin inclus. Ceci est 1 indexé. -n supprime l'écho de l'entrée en tant que sortie, ce que vous ne voulez manifestement pas; les nombres indiquent la plage de lignes sur laquelle la commande suivante doit être exécutée; la commande p affiche les lignes appropriées.

Assez simple en utilisant head / tail:

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

en utilisant sed:

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

en utilisant awk:

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

Vous pouvez utiliser "vi" puis la commande suivante:

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

Alternativement:

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

EDIT: - Juste pour ajouter une explication, utilisez head -n 16482 pour afficher les 16482 premières lignes, puis utilisez tail -n 258 pour obtenir les 258 dernières lignes de la première sortie.

Il existe une autre approche avec awk :

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

Si le fichier est volumineux, il peut être bon de quitter après avoir lu la dernière ligne souhaitée. De cette manière, les lignes suivantes ne seront pas lues inutilement:

awk 'NR==16224, NR==16482-1; NR==16482 {print; exit}' file
perl -ne 'print if 16224..16482' file.txt > new_file.txt
 # print section of file based on line numbers
 sed -n '16224 ,16482p'               # method 1
 sed '16224,16482!d'                 # method 2

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

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

devrait faire l'affaire. L'inconvénient de cette approche est que vous devez utiliser l'arithmétique pour déterminer l'argument de queue et pour déterminer si vous souhaitez que le terme 'entre' inclue la ligne de fin ou non.

Rapide et sale:

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

Ce n'est probablement pas la meilleure façon de le faire, mais cela devrait fonctionner.

BTW: 259 = 16482-16224 + 1.

J'ai écrit un programme Haskell appelé séparateur qui fait exactement cela: avoir un lisez mon billet de blog de sortie .

Vous pouvez utiliser le programme comme suit:

$ cat somefile | splitter 16224-16482

Et c’est tout ce qu’il ya à faire. Vous aurez besoin de Haskell pour l'installer. Juste:

$ cabal install splitter

Et vous avez terminé. J'espère que vous trouverez ce programme utile.

Même nous pouvons le faire pour vérifier en ligne de commande:

cat filename|sed 'n1,n2!d' > abc.txt

Par exemple:

cat foo.pl|sed '100,200!d' > abc.txt

Utilisation de ruby:

ruby -ne 'puts "#{$.}: #{

Utilisation de ruby:

<*>}" if $. >= 32613500 && $. <= 32614500' < GND.rdf > GND.extract.rdf

Debout sur les épaules de Boxxar, j'aime bien ceci:

sed -n '<first line>,$p;<last line>q' input

par exemple

sed -n '16224,$p;16482q' input

Le $ signifie "dernière ligne", donc la première commande permet à sed d’imprimer toutes les lignes commençant par la ligne 16224 et la deuxième commande oblige sed à quitter après la ligne d'impression 16428 . (L'ajout de 1 pour la plage q dans la solution de boxxar ne semble pas nécessaire.)

J'aime cette variante car je n'ai pas besoin de spécifier le numéro de la ligne de fin deux fois. Et j’ai mesuré qu’utiliser $ n’avait pas d’effets néfastes sur les performances.

J'étais sur le point de publier le tour de tête / queue, mais en fait, je ne ferais probablement que lancer Emacs. ; -)

  1. échap - x ligne goto ret 16224
  2. marque ( ctrl - espace )
  3. écha - x ligne goto ret 16482
  4. échap - w

ouvrez le nouveau fichier de sortie, ctl-y enregistrer

Voyons ce qui se passe.

Je voudrais utiliser:

awk 'FNR >= 16224 && FNR <= 16482' my_file > extracted.txt

FNR contient le numéro d'enregistrement (ligne) de la ligne lue dans le fichier.

J'ai écrit un petit script bash que vous pouvez exécuter à partir de votre ligne de commande, à condition de mettre à jour votre chemin PATH afin d'inclure son répertoire (ou de le placer dans un répertoire déjà contenu dans le chemin PATH).

Utilisation: $ pinch nom_fichier ligne de début ligne de fin

#!/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

Cela pourrait fonctionner pour vous (GNU sed):

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

ou en profitant de bash:

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

Je voulais faire la même chose à partir d'un script en utilisant une variable et y parvenir en mettant des guillemets autour de la variable $ pour séparer le nom de la variable du p:

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

Je souhaitais scinder une liste en plusieurs dossiers et trouvais la question initiale et la réponse utiles. (la commande divisée n'est pas une option sur l'ancien système d'exploitation auquel je dois porter le code).

Le -n dans les réponses acceptées fonctionne. Voici un autre moyen au cas où vous seriez enclin.

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

Cela fait ce qui suit:

  1. canaliser le contenu d'un fichier (ou insérer le texte comme vous le souhaitez).
  2. sed sélectionne la ligne donnée, l’affiche
  3. d est nécessaire pour supprimer des lignes, sinon sed supposera que toutes les lignes seront finalement imprimées. c'est-à-dire que sans le d, toutes les lignes imprimées par la ligne sélectionnée seront imprimées deux fois, car vous avez la partie $ {Linnum} p qui demande à être imprimée. Je suis à peu près sûr que le -n fait fondamentalement la même chose que le d ici.

Puisqu'on parle d'extraire des lignes de texte d'un fichier texte, je vais vous donner un cas particulier dans lequel vous souhaitez extraire toutes les lignes qui correspondent à un certain motif.

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

Imprime la ligne [Données] et le reste. Si vous voulez le texte de line1 dans le motif, vous tapez: sed -n '1, / Data / p' myfile. De plus, si vous connaissez deux modèles (il est préférable d’être unique dans votre texte), les lignes de début et de fin de la plage peuvent être spécifiées avec des correspondances.

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

Je pense que cela pourrait être une solution utile. Si le nom de la table est " personne " Vous pouvez utiliser sed pour obtenir toutes les lignes nécessaires à la restauration de votre table.

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

Sur la base de cette réponse , où il manque le champ DROP TABLE IF EXIST " pour la table que vous restaurez et vous devez supprimer quelques lignes du bas du nouveau fichier avant de l’utiliser pour éviter de supprimer la table suivante.

Des informations détaillées sont également disponibles ici

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top