Hoe laatste n personages te verwijderen uit een string in bash?

Ik heb een variabele varin een bash-script met een string, zoals:

echo $var
"some string.rtf"

Ik wil de laatste 4 tekens van deze tekenreeks verwijderen en het resultaat toewijzen aan een nieuwe variabele var2, zodat

echo $var2
"some string"

Hoe kan ik dit doen?


1, Autoriteit 100%

Ten eerste is het meestal beter om expliciet te zijn over uw intentie. Dus als u weet dat de tekenreeks eindigt in .rtf, en u wilt verwijderen die .rtf, kunt u gewoon gebruiken var2=${var%.rtf}. Eén potentieel bruikbaar aspect van deze aanpak is dat als de string niet eindigt eindigt in .rtf, het is helemaal niet gewijzigd; var2bevat een niet-gemodificeerde kopie van var.

Als u een FileName-achtervoegsel wilt verwijderen, maar niet weet of u precies wilt weten wat het is, kunt u var2=${var%.*}gebruiken om alles te verwijderen met de laatste .. Of, als u alleen alles wilt houden, maar niet het ., kunt u var2=${var%%.*}. Die opties hebben hetzelfde resultaat als er maar één is ., maar als er meer dan één is, kunt u kiezen welk einde van de tekenreeks te werken. Aan de andere kant, als er geen .In de reeks helemaal, var2wordt opnieuw een ongewijzigde kopie van var.

Als u echt een specifiek van tekens van tekens wilt verwijderen, zijn hier enkele opties.

Je hebt deze bashspecifiek getagd, dus we beginnen met bash-ingebouwde elementen. Degene die het langst heeft gewerkt, is dezelfde syntaxis voor het verwijderen van achtervoegsels die ik hierboven heb gebruikt: om vier tekens te verwijderen, gebruik var2=${var%????}. Of om alleen vier tekens te verwijderen als de eerste een punt is, gebruikt u var2=${var%.???}, dat is als var2=${var%.*}maar verwijdert alleen het achtervoegsel als het gedeelte na de punt precies drie tekens lang is. Zoals je kunt zien, moet je om tekens op deze manier te tellen één vraagteken per onbekend teken verwijderen, dus deze benadering wordt onpraktisch voor grotere subtekenreeksen.

Een optie in nieuwere shell-versies is extractie van substrings: var2=${var:0:${#var}-4}. Hier kunt u een willekeurig getal in plaats van de 4plaatsen om een ander aantal tekens te verwijderen. De ${#var}wordt vervangen door de lengte van de tekenreeks, dus dit vraagt eigenlijk om het extraheren en behouden van (lengte – 4) tekens, beginnend met de eerste (bij index 0). Met deze benadering verliest u de optie om de wijziging alleen aan te brengen als de tekenreeks overeenkomt met een patroon; wat de werkelijke waarde van de tekenreeks ook is, de kopie bevat alle behalve de laatste vier tekens.

Je kunt de startindex weglaten; het is standaard 0, dus je kunt dat inkorten tot gewoon var2=${var::${#var}-4}. In feite herkennen nieuwere versies van bash (met name 4+, wat betekent dat degene die met MacOS wordt geleverd niet zal werken) negatieve lengtes als de index van het teken om bij te stoppen, terugtellend vanaf het einde van de reeks. Dus in die versies kun je ook de tekenreekslengte-expressie verwijderen: var2=${var::-4}.

Als je niet echt bash gebruikt maar een andere POSIX-type shell, zal de op patronen gebaseerde achtervoegselverwijdering met %nog steeds werken – zelfs in een gewoon oud streepje, waar de op index gebaseerde substring extractie niet. Ksh en zsh ondersteunen beide substring-extractie, maar vereisen de expliciete 0-startindex; zsh ondersteunt ook de negatieve eindindex, terwijl ksh de lengte-expressie vereist. Merk op dat zsh, dat arraysindexeert vanaf 1, niettemin stringsindexeert vanaf 0 als je deze bash-compatibele syntaxisgebruikt. Maar met zsh kunt u ook scalaire parameters behandelen alsof het arrays van tekens zijn, in welk geval de syntaxis van de subtekenreeks een 1-gebaseerde telling gebruikt en de start- en (inclusief) eindposities tussen haakjes plaatst, gescheiden door komma’s: var2=$var[1,-5].

In plaats van de ingebouwde shell-parameteruitbreiding te gebruiken, kunt u natuurlijk een hulpprogramma uitvoeren om de tekenreeks te wijzigen en de uitvoer ervan vast te leggen met opdrachtvervanging. Er zijn verschillende commando’s die zullen werken; een daarvan is var2=$(sed 's/.\{4\}$//' <<<"$var").


Antwoord 2, autoriteit 95%

Je kunt het als volgt doen:

#!/bin/bash
v="some string.rtf"
v2=${v::-4}
echo "$v --> $v2"

Antwoord 3, autoriteit 91%

Gebruik ${var%????}om vier tekens aan het einde van de tekenreeks te verwijderen.

Om alles te verwijderen na de laatste .gebruik je ${var%.*}.


Antwoord 4, autoriteit 90%

Wat voor mij werkte was:

echo "hello world" | rev | cut -c5- | rev
# hello w

Maar ik gebruikte het om lijnen in een bestand bij te snijden, dus daarom ziet het er onhandig uit. Het echte gebruik was:

cat somefile | rev | cut -c5- | rev

cutbrengt je alleen zo ver als het trimmen van een startpositie, wat slecht is als je rijen met variabele lengte nodig hebt. Dus deze oplossing keert (rev) de string om en nu kunnen we betrekking hebben op zijn eindpositie, gebruikt dan cutzoals vermeld, en keert (opnieuw, rev) het terug naar zijn oorspronkelijke bestellen.


Antwoord 5, autoriteit 44%

Met behulp van Variabele uitbreiding/Substring vervanging:

${var/%Pattern/Replacement}

Als het achtervoegsel van var overeenkomt met Patroon, vervang dan Patroon door Vervanging.

Dus je kunt het volgende doen:

~$ echo ${var/%????/}
some string

Als alternatief,

Als je altijd dezelfde 4 letters hebt

~$ echo ${var/.rtf/}
some string

Als het altijd eindigt op .xyz:

~$ echo ${var%.*}
some string

Je kunt ook de lengte van de string gebruiken:

~$ len=${#var}
~$ echo ${var::len-4}
some string

of gewoon echo ${var::-4}


Antwoord 6, autoriteit 36%

Je zou sed kunnen gebruiken,

sed 's/.\{4\}$//' <<< "$var"

Voorbeeld:

$ var="some string.rtf"
$ var1=$(sed 's/.\{4\}$//' <<< "$var")
$ echo $var1
some string

7, Autoriteit 5%

Ik heb het volgende geprobeerd en het werkte voor mij:

#! /bin/bash
var="hello.c"
length=${#var}
endindex=$(expr $length - 4)
echo ${var:0:$endindex}

Uitgang: hel


8, Autoriteit 5%

In dit geval zou u Basename kunnen gebruiken, ervan uitgaande dat u hetzelfde achtervoegsel hebt op de bestanden die u wilt verwijderen.

Voorbeeld:

basename -s .rtf "some string.rtf"

Hierdoor wordt “sommige tekenreeks”

terug

Als u het achtervoegsel niet kent, en wilt u alles verwijderen na en inclusief de laatste punt:

f=file.whateverthisis
basename "${f%.*}"

Uitgangen “Bestand”

% betekent hakken ,. is wat u hakt, * is jokerteken


9, Autoriteit 3%

Dit werkte voor mij door het berekenen van de grootte van de reeks.
Het is eenvoudig dat u de waarde wilt weergeven die u moet retourneren en vervolgens opslaan zoals hieronder

removechars(){
        var="some string.rtf"
        size=${#var}
        echo ${var:0:size-4}  
    }
    removechars
    var2=$?

wat string


10

Dit kan ook de taak doen:

... | head -c -1
-c, --bytes=[-]NUM
              print the first NUM bytes of each file; with the leading '-', print all but the last NUM bytes of each file

Other episodes