Comment puis-je extraire une plage prédéterminée de lignes d'un fichier texte sous Unix?
J'ai un vidage SQL de ligne ~ 23000 contenant plusieurs bases de données d'une valeur de données. J'ai besoin d'extraire une partie de ce fichier (c'est à dire les données d'une base de données unique) et le placer dans un nouveau fichier. Je connais à la fois les numéros de ligne de début et de fin des données que je veux.
Est-ce que quelqu'un connaît une commande Unix (ou une série de commandes) pour extraire toutes les lignes d'un fichier entre la ligne 16224 et 16482, puis les rediriger dans un nouveau fichier?
21 réponses
sed -n '16224,16482p;16483q' filename > newfile
Du manuel sed :
P - Imprimer l'espace de motif (à 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 de motif, puis remplacez-le par la ligne d'entrée suivante. Si il n'y a plus d'entrée puis sed quitte sans traitement de plus commande.
Q - Exit
sed
sans traiter plus de commandes ou d'entrée. Notez que l'espace de motif actuel est imprimé si l'impression automatique n'est pas désactivée avec l'option-n.
Les adresses dans un script sed peuvent être sous l'une des formes suivantes:
Nombre La spécification d'un numéro de ligne correspond seulement 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 seconde correspond à l'adresse (inclusivement).
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, inclusivement. C'est 1-indexé. -n
supprime l'écho de l'entrée comme sortie, ce que vous ne voulez clairement pas; les chiffres indiquent la plage de lignes pour faire fonctionner la commande suivante; la commande p
imprime les lignes pertinentes.
Assez simple en utilisant la tête/queue:
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
Sinon:
cat file | head -n 16482 | tail -n 258
EDIT:- il suffit d'ajouter une explication, vous utilisez head-n 16482 pour afficher en premier 16482 lignes puis utilisez tail-n 258 pour obtenir les dernières 258 lignes de la première sortie.
Il y a une autre approche avec awk
:
awk 'NR==16224, NR==16482' file
Si le fichier est énorme, il peut être bon de exit
Après avoir lu la dernière ligne désirée. De cette façon, il ne lira pas inutilement le fichier jusqu'à la fin:
awk 'NR==16224, NR==16482-1; NR==16482 {print; exit}' file
# print section of file based on line numbers
sed -n '16224 ,16482p' # method 1
sed '16224,16482!d' # method 2
cat dump.txt | head -16224 | tail -258
Devrait faire l'affaire. L'inconvénient de cette approche est que vous devez faire l'arithmétique pour déterminer l'argument de la queue et pour tenir compte si vous voulez que le 'between' inclue la ligne de fin ou non.
Rapide et sale:
head -16428 < file.in | tail -259 > file.out
Probablement pas la meilleure façon de le faire, mais il devrait fonctionner.
BTW: 259 = 16482-16224 + 1.
J'étais sur le point de poster le tour tête/queue, mais en fait je ferais probablement juste lancer emacs. ;-)
- esc-x goto-line ret 16224
- marque (ctrl-l'espace)
- esc-x goto-line ret 16482
- ces-w
Ouvre 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 programme Haskell appelé splitter, ce qui fait exactement cela: avoir un lire ma version blog.
Vous pouvez utiliser le programme comme suit:
$ cat somefile | splitter 16224-16482
Et c'est tout ce qu'il y a à cela. 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 à la ligne de commande:
cat filename|sed 'n1,n2!d' > abc.txt
Par Exemple:
cat foo.pl|sed '100,200!d' > abc.txt
En utilisant ruby:
ruby -ne 'puts "#{$.}: #{$_}" if $. >= 32613500 && $. <= 32614500' < GND.rdf > GND.extract.rdf
J'ai écrit un petit script bash que vous pouvez exécuter à partir de votre ligne de commande, tant que vous mettez à jour votre chemin pour inclure son répertoire (ou vous pouvez le placer dans un répertoire déjà contenu dans le chemin).
Utilisation: $ pincée de nom de fichier de début de ligne fin de ligne
#!/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 utilisant une variable et l'ai réalisé 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 voulais diviser une liste en dossiers séparés et j'ai trouvé la question initiale et la réponse une étape utile. (la commande split 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 fonctionne. Voici une autre façon au cas où vous êtes enclin.
cat $filename | sed "${linenum}p;d";
Cela fait ce qui suit:
- conduit dans le contenu d'un fichier (ou alimente le texte comme vous le souhaitez).
- sed sélectionne la ligne donnée, l'imprime
- d est nécessaire pour supprimer des lignes, sinon sed supposera que toutes les lignes seront finalement imprimées. c'est-à-dire, sans le d, vous obtiendrez toutes les lignes imprimées par la ligne sélectionnée imprimée deux fois parce que vous avez la partie ${linenum}p en demandant qu'il soit imprimé. Je suis sûr que le-n fait essentiellement la même chose que le d ici.
Puisque nous parlons d'extraire des lignes de texte à partir d'un fichier texte, je vais donner un cas particulier où vous voulez 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
Imprimera la ligne [Data] et le reste. Si vous voulez que le texte de line1 au motif, vous tapez: sed - n '1,/Data / P' myfile. De plus, si vous connaissez deux motifs (mieux vaut être unique dans votre texte), la ligne de début et de fin de la plage peut être spécifiée avec des correspondances.
sed -n '/BEGIN_MARK/,/END_MARK/p' myfile
Je pense que cela pourrait être utile. Si le nom de la table est "person", vous pouvez utiliser sed pour obtenir toutes les lignes dont vous avez besoin pour restaurer votre table.
sed -n -e '/DROP TABLE IF EXISTS.*`person `/,/UNLOCK TABLES/p' data.sql > new_data.sql
Basé sur cette réponse , où il manque le "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 empêcher la suppression de la table suivante.
Des informations Détaillées peuvent également être trouvés ici