Cette ligne a fonctionné jusqu'à ce que je dispose d'espaces dans le deuxième champ.
svn status | grep '\!' | gawk '{print $2;}' > removedProjs
y at-il un moyen d'avoir awk tout imprimer en $ 2 ou plus? (3 $, 4 $ .. jusqu'à ce que nous n'avons plus de colonnes?)
Je suppose que je devrais ajouter que je le fais dans un environnement Windows avec Cygwin.
imprimera tout sauf la première colonne:
awk '{$1=""; print $0}' somefile
affichera toutes les premières colonnes sauf deux:
awk '{$1=$2=""; print $0}' somefile
Il y a une question en double avec un réponse plus simple using cut:
svn status | grep '\!' | cut -d\ -f2-
-d
spécifie le délimiteur (espace), -f
spécifie la liste des colonnes (commençant par la deuxième)
Vous pouvez utiliser une boucle for pour parcourir les champs d'impression $ 2 à $ NF (variable intégrée qui représente le nombre de champs sur la ligne).
Edit: Puisque "print" ajoute une nouvelle ligne, vous voudrez mettre les résultats en mémoire tampon:
awk '{out=""; for(i=2;i<=NF;i++){out=out" "$i}; print out}'
Sinon, utilisez printf:
awk '{for(i=2;i<=NF;i++){printf "%s ", $i}; printf "\n"}'
awk '{out=$2; for(i=3;i<=NF;i++){out=out" "$i}; print out}'
Ma réponse est basée sur celle de VeeArr , mais j'ai remarqué que cela commençait par un espace avant l'impression de la deuxième colonne (et du reste). Comme je n'ai qu'un point de réputation, je ne peux pas en parler, alors voici une nouvelle réponse:
commencez par "out" comme deuxième colonne, puis ajoutez toutes les autres colonnes (si elles existent). Cela va bien tant qu'il y a une deuxième colonne.
J'ai personnellement essayé toutes les réponses mentionnées ci-dessus, mais la plupart d'entre elles étaient un peu complexes ou tout simplement pas correctes. Le moyen le plus simple de le faire de mon point de vue est:
awk -F" " '{ for (i=4; i<=NF; i++) print $i }'
Où -F "" définit le délimiteur à utiliser par awk. Dans mon cas, il s’agit de l’espace, qui est aussi le délimiteur par défaut pour awk. Cela signifie que -F "" peut être ignoré.
Où NF définit le nombre total de champs/colonnes. Par conséquent, la boucle commencera du 4ème champ au dernier champ/colonne.
Où $ N récupère la valeur du Nième champ. Par conséquent, print $ i imprimera le champ/la colonne en cours en fonction du nombre de boucles.
La plupart des solutions avec awk laissent un espace. Les options ici évitent ce problème.
Une solution de découpe simple (fonctionne uniquement avec des délimiteurs simples):
command | cut -d' ' -f3-
Forcer un awk re-calcule parfois supprimer l’espace de début ajouté (OFS) en supprimant les premiers champs (fonctionne avec certaines versions de awk):
command | awk '{ $1=$2="";$0=$0;} NF=NF'
Imprimer chaque champ formaté avec printf
donnera plus de contrôle:
$ in=' 1 2 3 4 5 6 7 8 '
$ echo "$in"|awk -v n=2 '{ for(i=n+1;i<=NF;i++) printf("%s%s",$i,i==NF?RS:OFS);}'
3 4 5 6 7 8
Cependant, toutes les réponses précédentes modifient tous les FS répétés entre les champs en OFS. Construisons quelques options qui ne le font pas.
Une boucle avec sous pour supprimer les champs et les délimiteurs à l'avant.
Et en utilisant la valeur de FS au lieu de l’espace (qui peut être modifié).
Est plus portable et ne déclenche pas le changement de FS en OFS: REMARQUE: Le ^[FS]*
permet d’accepter une entrée comportant des espaces en tête.
$ in=' 1 2 3 4 5 6 7 8 '
$ echo "$in" | awk '{ n=2; a="^["FS"]*[^"FS"]+["FS"]+";
for(i=1;i<=n;i++) sub( a , "" , $0 ) } 1 '
3 4 5 6 7 8
Il est tout à fait possible de créer une solution qui n’ajoute pas d’espace (avant ou après) supplémentaire et qui préserve les espaces existants à l’aide de la fonction gensub
de GNU awk, comme ceci:
$ echo ' 1 2 3 4 5 6 7 8 ' |
awk -v n=2 'BEGIN{ a="^["FS"]*"; b="([^"FS"]+["FS"]+)"; c="{"n"}"; }
{ print(gensub(a""b""c,"",1)); }'
3 4 5 6 7 8
Il peut également être utilisé pour échanger un groupe de champs avec un nombre n
:
$ echo ' 1 2 3 4 5 6 7 8 ' |
awk -v n=2 'BEGIN{ a="^["FS"]*"; b="([^"FS"]+["FS"]+)"; c="{"n"}"; }
{
d=gensub(a""b""c,"",1);
e=gensub("^(.*)"d,"\\1",1,$0);
print("|"d"|","!"e"!");
}'
|3 4 5 6 7 8 | ! 1 2 !
Bien entendu, dans un tel cas, l'OFS est utilisé pour séparer les deux parties de la ligne et l'espace blanc de fin des champs est toujours imprimé.
NOTE: [FS]*
est utilisé pour autoriser les espaces de début dans la ligne d'entrée.
Cela m'énervait tellement, je me suis assis et j'ai écrit un analyseur de spécification de champ de type cut
- like, testé avec GNU Awk 3.1.7.
Commencez par créer un nouveau script de bibliothèque Awk appelé pfcut
, avec par exemple:.
Sudo nano /usr/share/awk/pfcut
Ensuite, collez le script ci-dessous et sauvegardez. Après cela, voici à quoi ressemble l'utilisation:
$ echo "t1 t2 t3 t4 t5 t6 t7" | awk -f pfcut --source '/^/ { pfcut("-4"); }'
t1 t2 t3 t4
$ echo "t1 t2 t3 t4 t5 t6 t7" | awk -f pfcut --source '/^/ { pfcut("2-"); }'
t2 t3 t4 t5 t6 t7
$ echo "t1 t2 t3 t4 t5 t6 t7" | awk -f pfcut --source '/^/ { pfcut("-2,4,6-"); }'
t1 t2 t4 t6 t7
Pour éviter de taper tout cela, je suppose que le mieux que l'on puisse faire (voir sinon Charger automatiquement une fonction utilisateur au démarrage avec awk? - Unix et Linux Stack Exchange ) est d'ajouter un alias à ~/.bashrc
; par exemple. avec:
$ echo "alias awk-pfcut='awk -f pfcut --source'" >> ~/.bashrc
$ source ~/.bashrc # refresh bash aliases
... alors vous pouvez simplement appeler:
$ echo "t1 t2 t3 t4 t5 t6 t7" | awk-pfcut '/^/ { pfcut("-2,4,6-"); }'
t1 t2 t4 t6 t7
Voici la source du script pfcut
:
# pfcut - print fields like cut
#
# sdaau, GNU GPL
# Nov, 2013
function spfcut(formatstring)
{
# parse format string
numsplitscomma = split(formatstring, fsa, ",");
numspecparts = 0;
split("", parts); # clear/initialize array (for e.g. `tail` piping into `awk`)
for(i=1;i<=numsplitscomma;i++) {
commapart=fsa[i];
numsplitsminus = split(fsa[i], cpa, "-");
# assume here a range is always just two parts: "a-b"
# also assume user has already sorted the ranges
#print numsplitsminus, cpa[1], cpa[2]; # debug
if(numsplitsminus==2) {
if ((cpa[1]) == "") cpa[1] = 1;
if ((cpa[2]) == "") cpa[2] = NF;
for(j=cpa[1];j<=cpa[2];j++) {
parts[numspecparts++] = j;
}
} else parts[numspecparts++] = commapart;
}
n=asort(parts); outs="";
for(i=1;i<=n;i++) {
outs = outs sprintf("%s%s", $parts[i], (i==n)?"":OFS);
#print(i, parts[i]); # debug
}
return outs;
}
function pfcut(formatstring) {
print spfcut(formatstring);
}
Cela fonctionnerait-il?
awk '{print substr($0,length($1)+1);}' < file
Cela laisse cependant quelques blancs devant.
Impression des colonnes à partir de # 2 (la sortie n'aura aucun espace de fin au début)
ls -l | awk '{sub(/[^ ]+ /, ""); print $0}'
echo "1 2 3 4 5 6" | awk '{ $NF = ""; print $0}'
celui-ci utilise awk pour tout imprimer sauf le dernier champ
Voici ce que j'ai préféré parmi toutes les recommandations:
Impression de la 6ème à la dernière colonne.
ls -lthr | awk '{out=$6; for(i=7;i<=NF;i++){out=out" "$i}; print out}'
ou
ls -lthr | awk '{ORS=" "; for(i=6;i<=NF;i++) print $i;print "\n"}'
Si vous avez besoin de colonnes spécifiques imprimées avec un délimiteur arbitraire:
awk '{print $3 " " $4}'
col # 3 col # 4
awk '{print $3 "anything" $4}'
col # 3anythingcol # 4
Ainsi, si vous avez des espaces dans une colonne, il y aura deux colonnes, mais vous pouvez le connecter avec n'importe quel délimiteur ou sans.
Cela fonctionnerait si vous utilisiez Bash et que vous pouviez utiliser autant de «x» que d'éléments que vous souhaitez supprimer et que plusieurs espaces seraient ignorés s'ils ne sont pas protégés.
while read x b; do echo "$b"; done < filename
Cette fonction awk
renvoie une sous-chaîne de $0
qui comprend des champs de begin
à end
:
function fields(begin, end, b, e, p, i) {
b = 0; e = 0; p = 0;
for (i = 1; i <= NF; ++i) {
if (begin == i) { b = p; }
p += length($i);
e = p;
if (end == i) { break; }
p += length(FS);
}
return substr($0, b + 1, e - b);
}
Pour tout obtenir à partir du champ 3:
tail = fields(3);
Pour obtenir la section de $0
qui couvre les champs 3 à 5:
middle = fields(3, 5);
b, e, p, i
non-sens dans la liste des paramètres de fonction est simplement un moyen awk
de déclarer des variables locales.
Perl:
@m=`ls -ltr dir | grep ^d | awk '{print \$6,\$7,\$8,\$9}'`;
foreach $i (@m)
{
print "$i\n";
}
Si vous ne voulez pas reformater la partie de la ligne que vous ne coupez pas, la meilleure solution à laquelle je peux penser est écrite dans ma réponse en:
Comment imprimer toutes les colonnes après un nombre particulier en utilisant awk?
Il coupe ce qui se trouve avant le numéro de champ N donné et imprime le reste de la ligne, y compris le numéro de champ N et le maintien de l'espacement d'origine (il ne reformate pas). Peu importe que la chaîne du champ apparaisse également ailleurs dans la ligne.
Définir une fonction:
fromField () {
awk -v m="\x01" -v N="$1" '{$N=m$N; print substr($0,index($0,m)+1)}'
}
Et utilisez-le comme ceci:
$ echo " bat bi iru lau bost " | fromField 3
iru lau bost
$ echo " bat bi iru lau bost " | fromField 2
bi iru lau bost
La sortie conserve tout, y compris les espaces de fin
Dans votre cas particulier:
svn status | grep '\!' | fromField 2 > removedProjs
Si votre fichier/flux ne contient pas de caractères de nouvelle ligne au milieu des lignes (vous utilisez peut-être un séparateur d'enregistrement différent), vous pouvez utiliser:
awk -v m="\x0a" -v N="3" '{$N=m$N ;print substr($0, index($0,m)+1)}'
Le premier cas échouera uniquement dans les fichiers/flux contenant le numéro de caractère hexadécimal rare 1
Je souhaite étendre les réponses proposées à la situation où les champs sont délimités par éventuellement plusieurs espaces blancs - la raison pour laquelle le PO n'utilise pas cut
je suppose.
Je sais que le PO a posé des questions sur awk
, mais une approche sed
fonctionnerait ici (exemple avec les colonnes imprimées du 5 au dernier):
approche pure sed
sed -r 's/^\s*(\S+\s+){4}//' somefile
Explication:
s///
est utilisé de manière standard pour effectuer une substitution^\s*
correspond à tout espace blanc consécutif au début de la ligne\S+\s+
signifie une colonne de données (caractères non blancs suivis de caractères blancs)(){4}
signifie que le motif est répété 4 fois.sed et couper
sed -r 's/^\s+//; s/\s+/\t/g' somefile | cut -f5-
en remplaçant simplement les espaces consécutifs par un seul onglet;
tr et cut: tr
peut également être utilisé pour presser des caractères consécutifs avec l'option -s
.
tr -s [:blank:] <somefile | cut -d' ' -f5-