Merci tout le monde. J'ai fini par utiliser 'cut -c1-2', honnêtement, je ne savais même pas que 'cut' était là. Je voudrais dire que je suis assez expérimenté en ligne de commande - mais apparemment j'ai beaucoup à apprendre.
Greg
1
@Greg, sachez simplement que cut est exécuté en tant que processus séparé - il sera plus lent que la solution interne de bash que j'ai postée à côté dans ma réponse. Cela ne fera aucune différence à moins que vous ne traitiez d'énormes ensembles de données, mais vous devez le garder à l'esprit.
paxdiablo
Edit En fait, je pense que cette ligne de code sera probablement exécutée environ 50 000 fois par rapport. Je pourrais donc simplement utiliser la méthode interne Bash - qui, comme vous l'avez dit, permettra d'économiser des ressources indispensables.
La méthode probablement la plus efficace, si vous utilisez le bashshell (et que vous semblez l'être, d'après vos commentaires), est d'utiliser la variante de sous-chaîne de l'expansion des paramètres:
pax> long="USCAGol.blah.blah.blah"
pax> short="${long:0:2}"; echo "${short}"
US
Il s'agira shortdes deux premiers caractères de long. Si longest plus court que deux caractères,short sera identique.
Cette méthode en shell est généralement meilleure si vous comptez le faire beaucoup (comme 50000 fois par rapport, comme vous le mentionnez) car il n'y a pas de surcharge de création de processus. Toutes les solutions qui utilisent des programmes externes souffriront de cette surcharge.
Si vous souhaitez également garantir une longueur minimale , vous pouvez le 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 élément de moins de deux caractères de longueur soit complété à droite avec des points (ou autre chose, simplement en changeant le caractère utilisé lors de la création tmpstr). Il n'est pas clair que vous en ayez besoin, mais j'ai pensé que je le mettrais pour être complet.
Cela dit, il existe un certain nombre de façons de le faire avec des programmes externes (par exemple si vous n'en avez pas bashà votre disposition), dont certaines sont:
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 ( cutet head) sont identiques pour une chaîne sur une seule ligne - ils ne vous renvoient que les deux premiers caractères. Ils diffèrent en ce que cutvous donnera les deux premiers caractères de chaque ligne ethead vous donnera les deux premiers caractères de toute l'entrée
Le troisième utilise la fonction de awksous-chaîne pour extraire les deux premiers caractères et le quatrième utilise des sedgroupes de capture (en utilisant ()et \1) pour capturer les deux premiers caractères et remplacer la ligne entière par eux. Ils sont tous deux similaires à cut- ils fournissent les deux premiers caractères de chaque ligne dans l'entrée.
Rien de tout cela n'a d'importance si vous êtes sûr que votre entrée est une seule ligne, ils ont tous un effet identique.
Je préfère utiliser printf '%s'au echocas où il y aurait des caractères étranges dans la chaîne: stackoverflow.com/a/40423558/895245 Pour les obsédés de POSIX: head -cn'est pas POSIX, cut -cet ne awk substrsont sed \1pas sûrs.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
1
@CiroSantilli 新疆 改造 中心 996ICU 六四 事件 en utilisant printf, vous n'avez même pas besoin d'un programme supplémentaire. Voyez ma réponse .
bschlueter
60
Le moyen le plus simple est
${string:position:length}
Où cela extrait la $lengthsous-chaîne à partir $stringde $position.
C'est un bash intégré, donc awk ou sed n'est pas nécessaire.
C'est le moyen le plus court, le plus simple et le plus simple d'obtenir la sous-chaîne.
ani627 le
34
Vous avez obtenu plusieurs bonnes réponses et j'irais avec le Bash intégré moi-même, mais depuis que vous avez posé des questions sur sedet awket ( presque ) personne d'autre n'a proposé de solutions basées sur elles, je vous propose celles-ci:
echo "USCAGoleta9311734.5021-120.1287855805"| sed 's/\(^..\).*/\1/'
L' awkun devrait être assez évident, mais voici une explication de l' sedun:
remplacer "s /"
le groupe "()" de deux caractères quelconques ".." commençant au début de la ligne "^" et suivi de n'importe quel caractère "." répété zéro fois ou plus "*" (les contre-obliques sont nécessaires pour échapper à certains caractères spéciaux)
par "/" le contenu du premier (et seul, dans ce cas) groupe (ici la barre oblique inverse est un échappement spécial faisant référence à une sous-expression correspondante)
Si vous souhaitez utiliser des scripts shell et ne pas compter sur des extensions non-posix (telles que les soi-disant bashismes), vous pouvez utiliser des techniques qui ne nécessitent pas de forger des outils externes tels que grep, sed, cut, awk, etc., qui alors rendre votre script moins efficace. Peut-être que l'efficacité et la portabilité posix ne sont pas importantes dans votre cas d'utilisation. Mais dans le cas où c'est le cas (ou juste comme une bonne habitude), vous pouvez utiliser la méthode d'option d' extension de paramètre suivante pour extraire les deux premiers caractères d'une variable shell:
$ sh -c 'var=abcde; echo "${var%${var#??}}"'
ab
Cela utilise l' expansion des paramètres "plus petit préfixe" pour supprimer les deux premiers caractères (c'est la ${var#??}partie), puis l' expansion des paramètres "plus petit suffixe" (le${var% partie) pour supprimer cette chaîne de caractères tout sauf les deux premiers de l'original valeur.
Cette méthode a été précédemment décrite dans cette réponse à la question "Shell = Vérifier si la variable commence par #". Cette réponse décrit également quelques 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 d'origine ici.
La meilleure réponse devrait être au top. pas de fourches, pas de bashismes. fonctionne même avec de petites coquilles telles que dash.
exore
1
Si votre système utilise un shell différent (pas bash), mais que votre système l'a fait bash, vous pouvez toujours utiliser la manipulation de chaîne inhérente de bashen appelant bashavec 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;"
Cela utilise la même méthode que la réponse principale , n'appelant que bashsi vous ne l'utilisez pas déjà.
palswim
Malheureusement, cela s'accompagne de tous les frais généraux liés à l'invocation d'un autre processus, mais parfois ces frais généraux n'ont pas autant d'importance que la simplicité et la familiarité.
palswim
1
Juste pour le plaisir, j'ajouterai quelques-uns qui, bien qu'ils soient trop compliqués et inutiles, n'ont pas été mentionnés:
étant donné qu'il / elle est susceptible d'appeler cela depuis le shell, une meilleure forme seraitperl -e 'print substr $ARGV[0], 0, 2' 'USCAGoleta9311734.5021-120.1287855805'
Réponses:
La méthode probablement la plus efficace, si vous utilisez le
bash
shell (et que vous semblez l'être, d'après vos commentaires), est d'utiliser la variante de sous-chaîne de l'expansion des paramètres:Il s'agira
short
des deux premiers caractères delong
. Silong
est plus court que deux caractères,short
sera identique.Cette méthode en shell est généralement meilleure si vous comptez le faire beaucoup (comme 50000 fois par rapport, comme vous le mentionnez) car il n'y a pas de surcharge de création de processus. Toutes les solutions qui utilisent des programmes externes souffriront de cette surcharge.
Si vous souhaitez également garantir une longueur minimale , vous pouvez le compléter au préalable avec quelque chose comme:
Cela garantirait que tout élément de moins de deux caractères de longueur soit complété à droite avec des points (ou autre chose, simplement en changeant le caractère utilisé lors de la création
tmpstr
). Il n'est pas clair que vous en ayez besoin, mais j'ai pensé que je le mettrais pour être complet.Cela dit, il existe un certain nombre de façons de le faire avec des programmes externes (par exemple si vous n'en avez pas
bash
à votre disposition), dont certaines sont:Les deux premiers (
cut
ethead
) sont identiques pour une chaîne sur une seule ligne - ils ne vous renvoient que les deux premiers caractères. Ils diffèrent en ce quecut
vous donnera les deux premiers caractères de chaque ligne ethead
vous donnera les deux premiers caractères de toute l'entréeLe troisième utilise la fonction de
awk
sous-chaîne pour extraire les deux premiers caractères et le quatrième utilise dessed
groupes de capture (en utilisant()
et\1
) pour capturer les deux premiers caractères et remplacer la ligne entière par eux. Ils sont tous deux similaires àcut
- ils fournissent les deux premiers caractères de chaque ligne dans l'entrée.Rien de tout cela n'a d'importance si vous êtes sûr que votre entrée est une seule ligne, ils ont tous un effet identique.
la source
printf '%s'
auecho
cas où il y aurait des caractères étranges dans la chaîne: stackoverflow.com/a/40423558/895245 Pour les obsédés de POSIX:head -c
n'est pas POSIX,cut -c
et neawk substr
sontsed \1
pas sûrs.Le moyen le plus simple est
Où cela extrait la
$length
sous-chaîne à partir$string
de$position
.C'est un bash intégré, donc awk ou sed n'est pas nécessaire.
la source
Vous avez obtenu plusieurs bonnes réponses et j'irais avec le Bash intégré moi-même, mais depuis que vous avez posé des questions sur
sed
etawk
et ( presque ) personne d'autre n'a proposé de solutions basées sur elles, je vous propose celles-ci:et
L'
awk
un devrait être assez évident, mais voici une explication de l'sed
un:la source
substr($0,1,2)
.Si vous êtes
bash
, vous pouvez dire:C'est peut-être exactement ce dont vous avez besoin…
la source
Juste grep:
la source
-P
option pour la raccourcir. Toutes les expressions régulières comprendront ce modèle.Vous pouvez utiliser
printf
:la source
colrm - supprime les colonnes d'un fichier
Pour laisser les deux premiers caractères, supprimez simplement les colonnes à partir de 3
la source
Assez tard en effet mais la voici
Ou
Ou
la source
Si vous souhaitez utiliser des scripts shell et ne pas compter sur des extensions non-posix (telles que les soi-disant bashismes), vous pouvez utiliser des techniques qui ne nécessitent pas de forger des outils externes tels que grep, sed, cut, awk, etc., qui alors rendre votre script moins efficace. Peut-être que l'efficacité et la portabilité posix ne sont pas importantes dans votre cas d'utilisation. Mais dans le cas où c'est le cas (ou juste comme une bonne habitude), vous pouvez utiliser la méthode d'option d' extension de paramètre suivante pour extraire les deux premiers caractères d'une variable shell:
Cela utilise l' expansion des paramètres "plus petit préfixe" pour supprimer les deux premiers caractères (c'est la
${var#??}
partie), puis l' expansion des paramètres "plus petit suffixe" (le${var%
partie) pour supprimer cette chaîne de caractères tout sauf les deux premiers de l'original valeur.Cette méthode a été précédemment décrite dans cette réponse à la question "Shell = Vérifier si la variable commence par #". Cette réponse décrit également quelques 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 d'origine ici.
la source
Si votre système utilise un shell différent (pas
bash
), mais que votre système l'a faitbash
, vous pouvez toujours utiliser la manipulation de chaîne inhérente debash
en appelantbash
avec une variable:la source
bash
si vous ne l'utilisez pas déjà.Juste pour le plaisir, j'ajouterai quelques-uns qui, bien qu'ils soient trop compliqués et inutiles, n'ont pas été mentionnés:
la source
la source
si mystring = USCAGoleta9311734.5021-120.1287855805
nous imprimerions
où 0 est la position de départ et 2 est comment lire les caractères meny
la source
awk
. Désolé, je n'ai pas pu le dire au début.C'est ce que vous recherchez?
ref: substr
la source
perl -e 'print substr $ARGV[0], 0, 2' 'USCAGoleta9311734.5021-120.1287855805'