Comment puis-je supprimer tout le texte après un caractère dans bash?

147

Comment puis-je supprimer tout le texte après un caractère, dans ce cas un deux-points (":"), dans bash? Puis-je aussi supprimer le côlon? Je ne sais pas comment faire.

Nathan
la source

Réponses:

135

Un exemple aurait pu être utile, mais si je vous ai bien compris, cela fonctionnerait:

echo "Hello: world" | cut -f1 -d":"

Cela convertira "bonjour: monde" en "bonjour".

Eldad Mor
la source
5
cutfonctionne, mais la réponse de Dennis est meilleure et plus flexible. Est-ce que quelqu'un sait si cela engendre un nouveau processus comme cut?
JoBu1324
3
Il est préférable d'utiliser les fonctionnalités d'extension de paramètres intégrées de Bash plutôt que de générer des sous-shell exécutant des outils tels que basenameet cut, voir la réponse de Dennis ci
Louis Maddox
1
cutpeut lire à partir de stdin, c'est donc mieux, surtout lorsque vous avez une très longue chaîne à traiter, comme le contenu d'un fichier.
Sahas
1
Et comment cela s'appliquerait hello: world. C'est une demi-réponse.
K - La toxicité du SO augmente.
Cela peut être fait en utilisant une syntaxe de substitution comme {var /: / ''}, mais ne fonctionne que dans bash ..
Mahesh le
265

Dans Bash (et ksh, zsh, tiret, etc.), vous pouvez utiliser l'expansion des paramètres avec %laquelle supprimera les caractères de la fin de la chaîne ou #qui supprimera les caractères du début de la chaîne. Si vous utilisez un seul de ces caractères, la plus petite chaîne correspondante sera supprimée. Si vous doublez le caractère, le plus long sera supprimé.

$ a='hello:world'
$ b=${a%:*}
$ echo "$b"
hello
$ a='hello:world:of:tomorrow'
$ echo "${a%:*}"
hello:world:of
$ echo "${a%%:*}"
hello
$ echo "${a#*:}"
world:of:tomorrow
$ echo "${a##*:}"
tomorrow
Suspendu jusqu'à nouvel ordre.
la source
6
Il s'agit d'une manipulation native de la chaîne shell, donc aucun processus supplémentaire ne sera généré. Référence Substitution de paramètres Bash , manipulation de chaînes Bash et meilleurs scripts Bash
Dodzi Dzakuma
@denniswilliamson Comment pourrais-je supprimer 2 caractères après une chaîne spécifique comme hello:worldle deviendra hello:woen utilisant ${a%:*}?
3kstc
Excellente réponse, merci beaucoup, mais ce sera bien d'ajouter aussi "${a##*:}"pour obtenir seulement tomorrow=)
avtomaton
1
@openCivilisation: Vous avez sans doute besoin d'utiliser la correspondance d'expression régulière alors: a='hello:world:of:tomorrow'; pattern=''^([^:]*:).*$'; [[$ a = ~ $ motif]]; echo "$ {BASH_REMATCH [1]}" `. Cela ne correspond que s'il y a un signe deux-points. Si vous voulez que ce soit facultatif, un modèle différent devrait être utilisé. Une explication des expressions rationnelles Bash (et des expressions rationnelles en général) dépasse le cadre de ces commentaires. Vous pouvez trouver d'autres questions qui en discutent ou publier les vôtres.
Suspendu jusqu'à nouvel ordre.
1
@ kp123: C'est le premier exemple de ma réponse. La deuxième fois que je le montre (où «demain» est supprimé), c'est presque exactement la situation dont vous parlez.
Suspendu jusqu'à nouvel ordre.
9
$ echo 'hello:world:again' |sed 's/:.*//'
hello
sk8asd123
la source
4
egrep -o '^[^:]*:'
cdhowie
la source
pouvez-vous expliquer comment interpréter cela, merci.
rɑːdʒɑ
1
egrepest grep avec -E. Cela ne fait aucune différence ici du régulier grep. -odemande à grep de n'imprimer que la partie de la ligne qui correspond à l'expression. ^ancre la correspondance au début d'une ligne. [^:]*correspond à zéro ou plusieurs caractères qui ne sont pas le :caractère. :correspond au caractère :.
cdhowie
Merci encore pour l'explication
rɑːdʒɑ
3

Disons que vous avez un chemin avec un fichier dans ce format:

/dirA/dirB/dirC/filename.file

Maintenant, vous ne voulez que le chemin qui comprend quatre "/". Type

$ echo "/dirA/dirB/dirC/filename.file" | cut -f1-4 -d"/"

et votre sortie sera

/dirA/dirB/dirC

L'avantage d'utiliser cut est que vous pouvez également découper le répertoire le plus haut ainsi que le fichier (dans cet exemple), donc si vous tapez

$ echo "/dirA/dirB/dirC/filename.file" | cut -f1-3 -d"/"

votre sortie serait

/dirA/dirB

Bien que vous puissiez faire la même chose de l'autre côté de la chaîne, cela n'aurait pas beaucoup de sens dans ce cas que de taper

$ echo "/dirA/dirB/dirC/filename.file" | cut -f2-4 -d"/"

résulte en

dirA/dirB/dirC

Dans certains autres cas, le dernier cas peut également être utile. Notez qu'il n'y a pas de "/" au début de la dernière sortie.

Nico Feulner
la source
2
Que faire si vous avez un répertoire "/resources/views/admin/users/relationships/posts.blade.php" et que vous voulez tout tronquer après la DERNIÈRE occurrence du "/", étant donné que vous ne savez pas combien "/ "les caractères sont dans la chaîne. Donc, ici, je voudrais que la sortie soit "/ resources / views / admin / users / relations /" (ou même / resources / views / admin / users / relations sans la barre oblique finale). Comment feriez-vous cela?
kp123
-1

couper tout après la dernière instance de ":"

cat fileListingPathsAndFiles.txt | grep -o '^.*:'

et si vous vouliez supprimer ce dernier ":"

cat file.txt | grep -o '^.*:' | sed 's/:$//'

@ kp123: vous voudriez remplacer :par /(où les deux-points sed devraient être \/)

S Hunter Simpson
la source