web-dev-qa-db-fra.com

Comment extraire les deux premiers caractères d'une chaîne dans un script Shell?

Par exemple, étant donné:

USCAGoleta9311734.5021-120.1287855805

Je veux extraire juste:

US
100
Greg

La méthode la plus efficace, si vous utilisez le shell bash (et vous semblez l'être, en fonction de vos commentaires), consiste à utiliser la variante de sous-chaîne de développement des paramètres:

pax> long="USCAGol.blah.blah.blah"
pax> short="${long:0:2}" ; echo "${short}"
US

Ceci définira short comme les deux premiers caractères de long. Si long est inférieur à deux caractères, short lui sera identique.

Cette méthode in-shell est généralement préférable si vous la pratiquez souvent (environ 50 000 fois par rapport, comme vous l'avez mentionné), car il n'y a pas de surcharge de création de processus. Toutes les solutions qui utilisent des programmes externes en souffriront.

Si vous souhaitez également assurer une longueur minimale , vous pouvez la compléter au préalable avec quelque chose comme:

pax> long="A"
pax> tmpstr="${long}.."
pax> short="${tmpstr:0:2}" ; echo "${short}"
A.

Cela garantirait que tout ce qui fait moins de deux caractères de long soit complété à droite par des points (ou autre chose, simplement en changeant le caractère utilisé lors de la création de tmpstr). Ce n’est pas clair que vous ayez besoin de cela, mais j’ai pensé que j’en ferais autant.


Cela dit, il existe différentes manières de procéder avec des programmes externes (par exemple, si vous n'avez pas bash disponible pour vous), parmi lesquelles:

short=$(echo "${long}" | cut -c1-2)
short=$(echo "${long}" | head -c2)
short=$(echo "${long}" | awk '{print substr ($0, 0, 2)}'
short=$(echo "${long}" | sed 's/^\(..\).*/\1/')

Les deux premiers (cut et head) sont identiques pour une chaîne d'une seule ligne - ils vous permettent en principe de vous restituer les deux premiers caractères. Ils diffèrent par le fait que cut vous donnera les deux premiers caractères de chaque ligne et que head vous donnera les deux premiers caractères de l’entrée entière.

Le troisième utilise la sous-chaîne awk pour extraire les deux premiers caractères et le quatrième utilise les groupes de capture sed (en utilisant () et \1) pour capturer les deux premiers caractères et remplacer la ligne entière avec eux. Ils sont tous deux similaires à cut - ils fournissent les deux premiers caractères de chaque ligne de l'entrée.

Peu importe si vous êtes certain que votre saisie ne concerne qu'une seule ligne, elles ont toutes le même effet.

158
paxdiablo

le plus simple est

${string:position:length}

Où cela extrait $length sous-chaîne de $string en $position.

C'est une bash intégrée, donc awk ou sed n'est pas nécessaire.

44
ennuikiller

Vous avez obtenu plusieurs bonnes réponses et je choisirais moi-même Bash, mais puisque vous avez posé des questions sur sed et awk et (presque), personne d'autre n'a proposé de solutions. basé sur eux, je vous offre ces:

echo "USCAGoleta9311734.5021-120.1287855805" | awk '{print substr($0,0,2)}'

et

echo "USCAGoleta9311734.5021-120.1287855805" | sed 's/\(^..\).*/\1/'

La awk devrait être assez évidente, mais voici une explication de la sed:

  • remplacer "s /"
  • le groupe "()" de deux caractères quelconques ".." commençant au début de la ligne "^" et suivi d'un caractère "". répété zéro ou plusieurs fois "*" (les barres obliques inverses sont nécessaires pour échapper à certains caractères spéciaux)
  • par "/" le contenu du premier groupe (et seulement, dans ce cas) (la barre oblique inverse est un échappement spécial faisant référence à une sous-expression correspondante)
  • terminé "/"
31
Dennis Williamson

Si vous êtes dans bash, vous pouvez dire:

bash-3.2$ var=abcd
bash-3.2$ echo ${var:0:2}
ab

C'est peut-être ce dont vous avez besoin…

7
Dominic Mitchell

Juste grep:

echo 'abcdef' | grep -Po "^.."        # ab
7
Amir Mehler

Assez tard, mais le voilà

sed 's/.//3g'

Ou

awk NF=1 FPAT=..

Ou

Perl -pe '$_=unpack a2'
4
Steven Penny

colrm - supprime les colonnes d'un fichier

Pour laisser les deux premiers caractères, il suffit de supprimer les colonnes à partir de 3

cat file | colrm 3
4
Ian Yang

Si vous souhaitez utiliser les scripts Shell et ne pas vous baser sur des extensions non posix (telles que les bashismes), vous pouvez utiliser des techniques ne nécessitant pas l'utilisation d'outils externes tels que grep, sed, cut, awk, etc. Rendez votre script moins efficace. Peut-être que l'efficacité et la portabilité posix ne sont pas importantes dans votre cas d'utilisation. Mais si c'est (ou juste comme bonne habitude), vous pouvez utiliser la méthode d'option de développement de paramètre suivante pour extraire les deux premiers caractères d'un shell. variable:

$ sh -c 'var=abcde; echo "${var%${var#??}}"'
ab

Ceci utilise le paramètre de développement "(plus petit préfixe) pour supprimer les deux premiers caractères (il s'agit de la partie ${var#??}), puis extension du paramètre "suffixe le plus petit" (la partie ${var%) pour supprimer cette chaîne composée de tous les caractères sauf les deux premiers caractères de la valeur d'origine.

Cette méthode a déjà été décrite dans cette réponse à la question "Shell = Vérifier si la variable commence par #". Cette réponse décrit également un couple de méthodes d’expansion de paramètres similaires qui peuvent être utilisées dans un contexte légèrement différent de celui qui s’applique à la question initiale.

1
Juan

Vous pouvez utiliser printf:

$ original='USCAGoleta9311734.5021-120.1287855805'
$ printf '%-.2s' "$orginal"
US
1
bschlueter

Si votre système utilise un autre shell (pas bash), mais que votre système possède bash, vous pouvez toujours utiliser la manipulation de chaîne inhérente de bash en appelant bash avec une variable:

strEcho='echo ${str:0:2}' # '${str:2}' if you want to skip the first two characters and keep the rest
bash -c "str=\"$strFull\";$strEcho;"
1
palswim
Perl -ple 's/^(..).*/$1/'
0
dsm

Est-ce ce que votre après?

my $string = 'USCAGoleta9311734.5021-120.1287855805';

my $first_two_chars = substr $string, 0, 2;

ref: substr

0
draegtun

si mystère = USCAGoleta9311734.5021-120.1287855805

print substr(mystring,0,2)

serait imprimer US

où 0 est la position de départ et 2 comment meny doit être lu

0
Jambobond