J'ai un dump SQL de ~ 23000 lignes contenant plusieurs bases de données. Je dois extraire une certaine section de ce fichier (c'est-à-dire les données d'une base de données unique) et 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.
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 vers un nouveau fichier?
sed -n '16224,16482p;16483q' filename > newfile
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 que sed sort sans traiter plus commandes.
q - Quittez
sed
sans traiter d'autres commandes ou entrées . 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 d'un script sed peuvent revêtir l'une des formes suivantes:
nombre Spécifier un numéro de ligne correspondra uniquement à 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 commençant par où la première adresse correspond, et continue jusqu'à la deuxième correspondances d'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 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 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
Alternativement:
cat file | head -n 16482 | tail -n 258
EDIT: - Juste pour ajouter une explication, vous 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 exit
après avoir lu la dernière ligne souhaitée. De cette manière, le fichier ne sera pas lu inutilement avant la fin:
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 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'étais sur le point de publier l'astuce tête/queue, mais en fait, je ne ferais probablement que lancer Emacs. ;-)
ouvrez le nouveau fichier de sortie, ctl-y save
Voyons ce qui se passe.
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
Utiliser Ruby:
Ruby -ne 'puts "#{$.}: #{$_}" if $. >= 32613500 && $. <= 32614500' < GND.rdf > GND.extract.rdf
J'utiliserais:
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 qui fait exactement ceci: avoir un lire mon post de blog de publication .
Vous pouvez utiliser le programme comme suit:
$ cat somefile | splitter 16224-16482
Et c'est tout ce qu'il y a à faire. Vous aurez besoin de Haskell pour l'installer. Juste:
$ cabal install splitter
Et vous avez terminé. J'espère que vous trouvez ce programme utile.
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
J'ai écrit un petit script bash que vous pouvez exécuter à partir de votre ligne de commande, tant que vous mettez à jour votre PATH afin d'inclure son répertoire (ou que vous puissiez le placer dans un répertoire déjà contenu dans le PATH).
Utilisation: $ pinch nom du fichier début
#!/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
Je voulais faire la même chose à partir d'un script en utilisant une variable et je 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 scinder une liste dans des dossiers distincts et j'ai trouvé la question initiale et sa réponse utiles. (La commande divisée n'est pas une option sur l'ancien OS, je dois porter le code).
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
Imprimera la ligne [Data] 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 (mieux vaut ê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
Debout sur les épaules de boxxar, j'aime bien ça:
sed -n '<first line>,$p;<last line>q' input
par exemple.
sed -n '16224,$p;16482q' input
Le $
signifie "dernière ligne". La première commande permet donc à sed
d'imprimer toutes les lignes commençant par la ligne 16224
et la deuxième commande à sed
quitter après en imprimant la ligne 16428
. (L'ajout de 1
pour la gamme 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é que l’utilisation de $
n’a pas d’effets néfastes sur les performances.
Le -n dans accepter les réponses fonctionne. Voici une autre façon au cas où vous êtes enclin.
cat $filename | sed "${linenum}p;d";
Cela fait ce qui suit: