J'ai un fichier nommé Element_query
contenant le résultat d'une requête:
SQL> select count (*) from element;
[Output of the query which I want to keep in my file]
SQL> spool off;
Je veux supprimer la 1ère ligne et la dernière ligne à l'aide de la commande Shell.
Utilisation de GNU sed
:
sed -i '1d;$d' Element_query
Comment ça marche:
-i
option modifie le fichier lui-même. Vous pouvez également supprimer cette option et rediriger la sortie vers un nouveau fichier ou une autre commande si vous le souhaitez.1d
supprime la première ligne (1
pour n'agir que sur la première ligne, d
pour la supprimer)$d
supprime la dernière ligne ($
pour n'agir que sur la dernière ligne, d
pour la supprimer)Pour aller plus loin:
1,5d
supprimerait les 5 premières lignes.SQL>
en utilisant l'instruction /^SQL> /d
/^$/d
statement1;statement2;satement3;...
) ou en les spécifiant séparément sur la ligne de commande (-e 'statement1' -e 'statement 2' ...
){ head -n[num] >/dev/null
head -n[num]
} <infile >outfile
Avec ce qui précède, vous pouvez spécifier le premier nombre de lignes à retirer de la tête de la sortie avec la première commande head
, et le nombre de lignes à écrire outfile
avec le second. Il le fera également plus rapidement que sed
- en particulier lorsque l'entrée est large - bien qu'il nécessite deux appels. Où sed
définitivement devrait être préféré cependant, c'est dans le cas où <infile
est pas un fichier régulier, lseekable - car cela fonctionnera généralement pas comme prévu dans ce cas, mais sed
peut gérer toutes les modifications de sortie dans un seul processus scripté.
Avec un GNU head
vous pouvez utiliser le -
forme négative pour [num]
dans la deuxième commande également. Dans ce cas, la commande suivante supprimera la première et la dernière ligne de l'entrée:
{ head -n1 >/dev/null
head -n-1
} <infile >outfile
sed
:Supposons, par exemple, que je lisais une entrée de 20 lignes et que je voulais supprimer les 3 premiers et les 7 derniers. Si je décidais de le faire avec sed
, je le ferais avec un tampon de queue. Je voudrais d'abord additionner trois et sept pour un nombre total de bandes de dix, puis faire:
seq 20 | sed -ne:n -e '3d;N;1,10bn' -eP\;D
C'est un exemple qui supprime les 3 et 7 dernières lignes de l'entrée. L'idée est que vous pouvez mettre en mémoire tampon autant de lignes que vous souhaitez supprimer de la queue de l'entrée dans l'espace de motif sur une pile, mais seulement P
rint la première de ces lignes pour chaque ligne tirée.
1,10
sed
P
n'imprime rien car pour chacun d'entre eux, il empile les entrées ligne par ligne dans un espace modèle dans une boucle b
ranch.sed
est d
eleted - et donc les 3 premières lignes sont supprimées de la sortie d'un seul coup.sed
atteint le $
la dernière ligne d'entrée et tente d'extraire le N
ext il frappe EOF et arrête complètement le traitement. Mais à ce moment-là, l'espace de modèle contient toutes les lignes 14,20
- dont aucun n'a encore été P
imprimé, et ne le sont jamais.sed
P
imprime uniquement jusqu'à la première occurrence \n
ewline dans l'espace modèle, et D
eletes même avant de commencer un nouveau cycle avec ce qui reste - ou les 6 lignes d'entrée suivantes. La 7ème ligne est à nouveau ajoutée à la pile avec la commande N
ext dans le nouveau cycle.Et donc, de la sortie de seq
(qui est 20 lignes numérotées séquentiellement), sed
affiche uniquement:
4
5
6
7
8
9
10
11
12
13
Cela devient problématique lorsque le nombre de lignes que vous souhaitez supprimer de la queue d'entrée est important, car les performances de sed
sont directement proportionnelles à la taille de son espace de motif. Néanmoins, c'est une solution viable dans de nombreux cas - et POSIX spécifie un espace de modèle sed
pour gérer au moins 4 Ko avant de se casser.
Essayez cette solution:
tail -n +2 name_of_file | head -n-1
Personnalisation
Vous pouvez facilement l'adapter pour supprimer les n premières lignes en changeant le +2
de (tail
;
ou pour supprimer les n dernières lignes en changeant le -1
de head
.
Vous pouvez sélectionner les lignes entre une plage dans awk
(cela suppose que vous connaissez le nombre de lignes):
awk 'NR>1 && NR < 3' file
Ou en Perl:
Perl -ne 'print if $.>1 && $.<3' file
Si vous ne savez pas combien de lignes il y a, vous pouvez le calculer à la volée en utilisant grep
(notez que cela ne comptera pas les lignes vides, utilisez grep -c '' file
pour les compter également):
awk -vm="$(grep -c . file2.txt)" 'NR>1 && NR<m' file2.txt
Je ne vais pas vous dire comment supprimer un certain nombre de lignes. Je vais attaquer le problème de cette façon:
grep -v '#SQL>' Element_query >outfile
Au lieu de compter les lignes, il élimine les commandes SQL en reconnaissant les invites. Cette solution peut ensuite être généralisée pour d'autres fichiers de sortie de sessions SQL avec plus de commandes que deux.
ed
est "l'éditeur de texte standard" et devrait être disponible sur les systèmes qui n'ont pas GNU sed
. Il a été initialement conçu comme un éditeur de texte, mais il est bien adapté aux scripts.
printf '%s\n' 1d '$d' w q | ed Element_query
1d
supprime la première ligne du fichier, $d
(cité pour que le Shell ne pense pas que ce soit une variable) supprime la dernière ligne, w
écrit le fichier et q
quitte ed
. printf
est ici utilisé pour formater les commandes pour ed
- chacune doit être suivie d'une nouvelle ligne; il existe bien sûr d'autres moyens d'y parvenir.
Vous seriez bien mieux servi par couper les commandes SQL. Vous pouvez le faire de deux manières:
Si vous êtes absolument sûr que la séquence "SQL>
"ne pas se produit n'importe où ailleurs dans la sortie,
grep -v -F 'SQL> ' < infile > outfile
Si vous n'êtes pas aussi sûr,
grep -v '^SQL> .*;$' < infile > outfile
La deuxième version est plus lente mais plus précise: elle ignorera les lignes commençant exactement par "SQL>" et se terminant par un point-virgule, qui semblent décrire les lignes que vous souhaitez éliminer.
Cependant, il serait préférable de ne pas mettre cette sortie supplémentaire dans le fichier pour commencer. La plupart des systèmes SQL ont un moyen de le faire. Je ne connais pas trop Oracle, mais peut-être cette réponse pourrait être utile.
Il existe plusieurs façons de supprimer les lignes de début et de fin d'un fichier.
Vous pouvez utiliser awk
car il gère à la fois la correspondance de motifs et le comptage de lignes,
#you need to know length to skip last line, assume we have 100 lines
awk 'NR>1 && NR<100 {print $0};' < inputfile
#or
awk '/SQL/ {next}; {print $0;};' < inputfile |awk 'NR>1&& NR<10 {print $0};'
Vous pouvez utiliser grep -v
pour exclure les lignes que vous ne voulez pas par motif, et vous pouvez faire correspondre plusieurs motifs en utilisant le -E
option,
grep -v -E "SQL>" < inputfile > outputfile
Vous pouvez utiliser head
et tail
pour découper des nombres spécifiques de lignes,
lines=$((`wc -l < inputfile`-2)) #how many lines in file, less 2
head -n-1 < inputfile | head -n$lines > outputfile
#or
tail -n+2 < inputfile | head -n$lines > outputfile
Vous pouvez utiliser vi/vim
, et supprimez la première et la dernière ligne (s),
vi inputfile
:1
dd
:$
dd
:w! outputfile
:x
vous pouvez utiliser un script Perl, sauter la première ligne, enregistrer chaque ligne, imprimer lorsque vous obtenez une ligne suivante,
#left as exercise for the reader :-)
Utilisation de awk
:
< inputfile awk 'NR>1 {print r}; {r=$0}' > outputfile
< inputfile
: redirige le contenu de inputfile
vers awk
stdin
> outputfile
: redirige le contenu de awk
stdout
vers outputfile
NR>1
: exécute les actions suivantes uniquement si le numéro de l'enregistrement en cours de traitement est supérieur à 1{print r}
: affiche le contenu de la variable r
{r=$0}
: affecte le contenu de l'enregistrement en cours de traitement à la variable r
Ainsi, lors de la première exécution du script awk
, le premier bloc d'actions n'est pas exécuté, tandis que le deuxième bloc d'actions est exécuté et le contenu de l'enregistrement est affecté à la variable r
; lors de la deuxième exécution, le premier bloc d'actions est exécuté et le contenu de la variable r
est imprimé (donc l'enregistrement précédent est imprimé); cela a pour effet d'imprimer chaque ligne traitée mais la première et la dernière.