6

I have a list of files (basically they are .deb packages). Let's say:

abc-de-1.2.3-1.deb
fgh-ij-4.5.6-2.deb
klm-no-7.8.9-3.deb
pqrs-10.11.12-4.deb
...

As you can see some of the file names have numbers after a - while others have some text after a - and then numbers after the next -.

Are there any ways to remove everything starting from the numbers including the -, i.e.,

abc-de
fgh-ij
klm-no
pqrs
...

I want to edit the list, not rename the files.

  • it seems you want to cut of always from the second - from the right. Is that always the case? – Jacob Vlijm Jul 23 '17 at 6:53
  • @JacobVlijm - For the last filename its the first -. – Raphael Jul 23 '17 at 6:54
  • No it isn't, second hyphen from the right :) – Jacob Vlijm Jul 23 '17 at 6:56
  • @JacobVlijm - Oh sorry! No that's not always the case – Raphael Jul 23 '17 at 6:59
  • @JacobVlijm See Zanna's answer. OP wants to delete everything starting from the first number, reading left to right. It's basically "-".join([ i for i in "abc-de-1.2.3-1.deb".split("-") if not re.match('[0-9]', i) ]) in pythonic terms – Sergiy Kolodyazhnyy Jul 23 '17 at 7:01
8

If you're able to use the first number to identify what you want to remove every time, you could use:

$ sed 's/-[0-9].*//' file
abc-de
fgh-ij
klm-no
pqrs

Notes

  • s/old/new/ replace old with new
  • [0-9] some digit
  • .* any number of any characters
  • Will it work if the list of filenames are in a text file? – Raphael Jul 23 '17 at 6:34
  • @Raphael do you want to edit the list itself, or the names of only the files in the list? If the latter, where are the files? Are they in a directory with other things that you don't want to rename and that can't be distinguished from them using shell wildcards, or in multiple directories? – Zanna Jul 23 '17 at 6:37
  • I have the filenames in a txt file and I want to edit the names in that file, i.e., I want to edit the list. – Raphael Jul 23 '17 at 6:41
  • @Raphael OK, I don't understand what exactly you want to alter. The actual files or only the list that you have ? Do you want the command to read the list and rename debs, or do you want command to only edit your list and not touch real debs ? – Sergiy Kolodyazhnyy Jul 23 '17 at 6:43
  • 1
    @Raphael you can use the same regex on rename utility if the files are actually exists rename 's/-[0-9].*//' *.deb – Avinash Raj Jul 24 '17 at 5:52
6

Using grep with Perl regular expressions:

$ grep -Po "^[a-z-]*(?=-[0-9])" filename
abc-de
fgh-ij
klm-no
pqrs
4

Perl

$ perl -lne 's/([[:digit:]].*)//;s/-$//;print' input.txt                                                            
abc-de
fgh-ij
klm-no
pqrs

This performs two substitutions, one to delete everything that starts with a digit, and removes trailing -. Use -i options additionally to edit original file, like $ perl -i -lne 's/([[:digit:]].*)//;s/-$//;print' input.txt

Alternatively, with greedy non-digit match and grouping:

$ perl -lne 's/^(\D*)-.*/\1/;print' input.txt                                                                                                        
abc-de
fgh-ij
klm-no
pqrs

AWK

$ awk -F '-' '{s=$1;for(i=2;i<=NF;i++) if($i~/[0-9].*/){print s;next}else{s=s"-"$i}}' input.txt 
abc-de
fgh-ij
klm-no
pqrs

The way this works is that we treat - as separator for fields, then iterate over each line. We "cache" the first field, and move on iterating using for loop. On each iteration we check if the column doesn't contain a number we pad it to s variable. If the column contains a number - we print what we saved up and move on to next line.

Use > new_file.txt at the end to redirect output to new file.

Python

#!/usr/bin/env python
import sys,re

with open(sys.argv[1]) as f:
    for line in f:
        tokens = re.split("-|\.",line.strip().replace(".deb",""))
        words_only = filter(lambda x: not x.isdigit(),tokens)
        print("-".join(words_only))

Using re.split() we break down every line into list of tokens, and filter only non-digit tokens.

Alternatively, here's a one-liner command. This doesn't take pre-caution of in case there's no digit in line, so only use this if you're sure all lines contain numbers.

$ python -c 'import re,sys;f=open(sys.argv[1]);print("\n".join([ l[:re.search(r"\d",l).start()-1] for l in f]))' input.txt

Potential numbers in package names

hvd properly noted in the comments that there may be integers in package names sometimes, which may present a difficulty with parsing the input file, while version names typically have dots in them. With that in mind, the commands can be altered somewhat to counter that:

$ perl -lne 's/\d*\..*//;s/-$//;print' input.txt

$ awk '{gsub(/[0-9]*\..*/,"");print substr($0,0,length($0)-1)};' input.txt                                                                           

$ python -c 'import re,sys;f=open(sys.argv[1]);print("\n".join([ l[:re.search(r"\d*\.",l).start()-1] for l in f]))' input.txt
  • 1
    Haha, nice, but the python version might be a bit verbose for the job :) – Jacob Vlijm Jul 23 '17 at 7:27
  • @JacobVlijm, well, i could turn it into one liner or use re.match but that's be repeating same thing as sed or perl answers – Sergiy Kolodyazhnyy Jul 23 '17 at 7:44
  • Your Perl answer assumes the first digit will immediately follow a - symbol, but the OP's input looks like package names and versions, and it's not uncommon for package names to include digits as well. – hvd Jul 23 '17 at 9:13
  • @hvd good point , however that probably should be commented towards OP, not my answer (or other answers, for that matter). They asked remove everything starting from the numbers including the -, so I provided what they asked. If they do have other type of packages in the list, I can revise the answer, but OP has to explicitly say so – Sergiy Kolodyazhnyy Jul 23 '17 at 9:20
  • @SergiyKolodyazhnyy The question specifies "numbers after a -" in the sentence before the one you're referring to, so personally, I think the question is clear enough as it is. – hvd Jul 23 '17 at 9:26
4

Through awk,

awk -F'-[0-9]' '{print $1}' file

In awk, we can also pass a regex as an argument to Field Separator -F. So this would split each row on the part where the regex matches.

Example:

$ echo 'abc-de-1.2.3-1.deb' | awk -F'-[0-9]' '{print $1}'
abc-de
1

I'll make a guess, since you suggested the files are DEB packages, then, perhaps you wanted something like:

dpkg-query -f '${Package}\n' -W 'gnome*'

Where, instead of gnome*, you could substitute any pattern. I'm not sure what exactly the convention is for naming DEB archives, but if those are DEB archives, it's probably best to rely on dpkg to give you the package name.

And if those are DEB archive files (on your system), then you could use:

dpkg-deb --showformat='${Package}\n' -W some-file.deb 

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.