У меня есть список файлов (в основном это .deb пакеты). Предположим:
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
...
Как вы можете видеть, некоторые имена файлов имеют номера после -, в то время как другие имеют некоторый текст после -, а затем цифры после следующего -. [ ! d1]
Есть ли способ удалить все, начиная с чисел, включая -, т. е.
abc-de
fgh-ij
klm-no
pqrs
...
Я хочу редактировать список, а не переименовывать файлы.
Если вы можете использовать первый номер для определения того, что хотите удалить каждый раз, вы можете использовать:
$ sed 's/-[0-9].*//' file
abc-de
fgh-ij
klm-no
pqrs
Если вы можете использовать первый номер для определения того, что хотите удалить каждый раз, вы можете использовать:
$ sed 's/-[0-9].*//' file
abc-de
fgh-ij
klm-no
pqrs
Используя grep с регулярными выражениями Perl:
$ grep -Po "^[a-z-]*(?=-[0-9])" filename
abc-de
fgh-ij
klm-no
pqrs
$ perl -lne 's/([[:digit:]].*)//;s/-$//;print' input.txt
abc-de
fgh-ij
klm-no
pqrs
Выполняет две замены: одну, чтобы удалить все, что начинается с цифры, и удаляет трейлинг -. Используйте -i дополнительные опции для редактирования исходного файла, например $ perl -i -lne 's/([[:digit:]].*)//;s/-$//;print' input.txt
. Альтернативно, с жадным несоответствием и группировкой цифр:
$ perl -lne 's/^(\D*)-.*/\1/;print' input.txt
abc-de
fgh-ij
klm-no
pqrs
$ 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
] Как это работает, мы рассматриваем - как разделитель для полей, а затем итерацию по каждой строке. Мы «кэшируем» первое поле и перемещаемся по итерации с использованием цикла for. На каждой итерации мы проверяем, не содержит ли столбец номер, который мы вставляем в переменную s.
Используйте > new_file.txt в конце для перенаправления вывода в новый файл.
#!/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))
Используя re.split(), мы разбиваем каждую строку на список токенов и фильтруем только нецифровые маркеры.
В качестве альтернативы, это команда с одним слоем. Это не требует предварительного предупреждения в случае отсутствия цифры в строке, поэтому используйте это, только если вы уверены, что все строки содержат числа.
$ 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
hvd должным образом отметил в комментариях, что иногда могут быть целые числа в именах пакетов, что может представлять трудности при анализе входного файла, в то время как имена версий обычно имеют точки в них. Имея это в виду, команды могут быть несколько изменены, чтобы противостоять этому:
$ 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
Через awk,
awk -F'-[0-9]' '{print $1}' file
В awk мы также можем передать регулярное выражение в качестве аргумента в полевой разделитель -F. Таким образом, это разделило бы каждую строку на ту часть, где соответствует регулярное выражение.
Пример:
$ echo 'abc-de-1.2.3-1.deb' | awk -F'-[0-9]' '{print $1}'
abc-de
Я буду предполагать, так как вы предположили, что файлы являются пакетами DEB, тогда, возможно, вам нужно что-то вроде:
dpkg-query -f '${Package}\n' -W 'gnome*'
Где вместо gnome* вы можете заменить любой шаблон , Я не уверен, что такое соглашение об именах архивов DEB, но если это архивы DEB, лучше всего полагаться на dpkg, чтобы дать вам имя пакета.
И если это DEB архивных файлов (в вашей системе), вы можете использовать:
dpkg-deb --showformat='${Package}\n' -W some-file.deb
Через awk,
awk -F'-[0-9]' '{print $1}' file
В awk мы также можем передать регулярное выражение в качестве аргумента в полевой разделитель -F. Таким образом, это разделило бы каждую строку на ту часть, где соответствует регулярное выражение.
Пример:
$ echo 'abc-de-1.2.3-1.deb' | awk -F'-[0-9]' '{print $1}'
abc-de
Используя grep с регулярными выражениями Perl:
$ grep -Po "^[a-z-]*(?=-[0-9])" filename
abc-de
fgh-ij
klm-no
pqrs
$ perl -lne 's/([[:digit:]].*)//;s/-$//;print' input.txt
abc-de
fgh-ij
klm-no
pqrs
Выполняет две замены: одну, чтобы удалить все, что начинается с цифры, и удаляет трейлинг -. Используйте -i дополнительные опции для редактирования исходного файла, например $ perl -i -lne 's/([[:digit:]].*)//;s/-$//;print' input.txt
. Альтернативно, с жадным несоответствием и группировкой цифр:
$ perl -lne 's/^(\D*)-.*/\1/;print' input.txt
abc-de
fgh-ij
klm-no
pqrs
$ 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
] Как это работает, мы рассматриваем - как разделитель для полей, а затем итерацию по каждой строке. Мы «кэшируем» первое поле и перемещаемся по итерации с использованием цикла for. На каждой итерации мы проверяем, не содержит ли столбец номер, который мы вставляем в переменную s.
Используйте > new_file.txt в конце для перенаправления вывода в новый файл.
#!/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))
Используя re.split(), мы разбиваем каждую строку на список токенов и фильтруем только нецифровые маркеры.
В качестве альтернативы, это команда с одним слоем. Это не требует предварительного предупреждения в случае отсутствия цифры в строке, поэтому используйте это, только если вы уверены, что все строки содержат числа.
$ 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
hvd должным образом отметил в комментариях, что иногда могут быть целые числа в именах пакетов, что может представлять трудности при анализе входного файла, в то время как имена версий обычно имеют точки в них. Имея это в виду, команды могут быть несколько изменены, чтобы противостоять этому:
$ 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
Я буду предполагать, так как вы предположили, что файлы являются пакетами DEB, тогда, возможно, вам нужно что-то вроде:
dpkg-query -f '${Package}\n' -W 'gnome*'
Где вместо gnome* вы можете заменить любой шаблон , Я не уверен, что такое соглашение об именах архивов DEB, но если это архивы DEB, лучше всего полагаться на dpkg, чтобы дать вам имя пакета.
И если это DEB архивных файлов (в вашей системе), вы можете использовать:
dpkg-deb --showformat='${Package}\n' -W some-file.deb