@MestreLion Часто люди читают вопрос, чтобы найти решение проблемы. Это начинается с ложной предпосылки, которая cutподдерживает то, чего нет. Но я подумал, что это было полезно, так как заставляет читателя обдумывать код, за которым легче следовать. Я хотел быстрый, простой способ использовать cutбез необходимости использования нескольких синтаксисов для awk, grep, sedи т.д. , revчто сделал трюк; очень элегантно, и то, что я никогда не рассматривал (даже если неуклюжий для других ситуаций). Мне также понравилось читать другие подходы из других ответов.
Бежор
3
Пришла настоящая проблема: я хочу найти все различные расширения файлов в дереве исходных текстов, чтобы обновить файл .gitattributes. Так же find | cut -d. -f<last>как и естественная склонность
Studog
Ответы:
680
Вы можете попробовать что-то вроде этого:
echo 'maps.google.com'| rev | cut -d'.'-f 1| rev
объяснение
rev меняет "maps.google.com" на moc.elgoog.spam
cut использует точку (т. е. «.») в качестве разделителя и выбирает первое поле, которое moc
Это не только использование, cutно это без sedили. Так awkчто думают OP?
Джаеш Бхой
7
@tom OP задала больше вопросов, чем просто за последние несколько часов. Основываясь на наших взаимодействиях с OP, мы знаем, что awk / sed / etc. не допускаются в его домашнем задании, но ссылка на rev не была сделана. Так что это стоило того
zedfoxus
4
@zfus я вижу. Может быть, захочется вставить другой revпотом.
Том
17
двойной revотличный идеал!
Ford Guo
6
Удивительно, просто, прекрасно, спасибо за объяснение тоже - не хватает людей, объясняющих каждый шаг в длинных цепочках переданных команд
Пит
128
Используйте расширение параметра. Это намного эффективнее, чем любая другая внешняя команда cut(или grep) включена.
data=foo,bar,baz,qux
last=${data##*,}
Смотрите BashFAQ # 100 для ознакомления с нативной обработкой строк в bash.
@ErwinWessels: потому что bash очень медленный. Используйте bash для запуска конвейеров, а не для массовой обработки данных. Я имею в виду, это замечательно, если у вас уже есть одна строка текста в переменной оболочки, или если вы хотите while IFS= read -ra array_var; do :;done <(cmd)обработать несколько строк. Но для большого файла rev | cut | rev, вероятно, быстрее! (И, конечно, awk будет быстрее, чем это.)
Питер Кордес
2
@PeterCordes, awk будет быстрее для больших файлов, конечно, но для преодоления затрат на запуск с постоянным коэффициентом требуется немалый вклад. (Существуют также оболочки - например, ksh93 - с производительностью, близкой к awk, где синтаксис, приведенный в этом ответе, остается действительным; bash исключительно вялый, но даже близко не подходит к единственной доступной опции).
Чарльз Даффи
1
Спасибо @PeterCordes; как обычно, я думаю, у каждого инструмента есть свои варианты использования.
Эрвин Вессельс
1
На сегодняшний день это самый быстрый и краткий способ обрезки одной переменной внутри bashскрипта (при условии, что вы уже используете bashскрипт). Не нужно называть что-либо внешним.
Кен Шарп
1
@Balmipour ... однако, revявляется специфическим для любой ОС вы используете , что обеспечивает его - это не стандартизировано во всех системах UNIX. Смотрите список глав для раздела POSIX по командам и утилитам - его там нет. И на самом деле не${var##prefix_pattern} относится к bash; он соответствует стандарту POSIX sh , см. конец раздела 2.6.2 (связанный), поэтому в отличие от него он всегда доступен в любой совместимой оболочке. rev
Чарльз Даффи
89
Это невозможно, используя просто cut. Вот способ использования grep:
Чтобы сделать наоборот, и найти все, кроме последнего поля, сделайте:grep -o '^.*,'
Ариэль
2
Это было особенно полезно, потому что revдобавить проблему многобайтовых символов Unicode в моем случае.
Брайс
3
Я пытался сделать это на MinGW, но моя версия grep не поддерживает -o, поэтому я использовал, sed 's/^.*,//'который заменяет все символы до и включая последнюю запятую на пустую строку.
TamaMcGlinn
46
Без awk? ... Но это так просто с awk:
echo 'maps.google.com'| awk -F.'{print $NF}'
AWK - намного более мощный инструмент, чтобы иметь в своем кармане. -F если для разделителя полей NF - количество полей (также обозначает индекс последнего)
Это универсально и работает точно так, как и ожидалось каждый раз. В этом сценарии использование cutдля достижения конечного результата ОП аналогично использованию ложки для «нарезки» стейка (каламбур предназначен :)). awkэто нож для стейка.
Hickory420
3
Избегайте ненужного использования, echoкоторое может замедлить работу скрипта для длинных файлов awk -F. '{print $NF}' <<< 'maps.google.com'.
Anil_M
14
Есть несколько способов. Вы можете использовать это тоже.
Используя это решение, количество полей действительно может быть неизвестно и время от времени изменяться. Однако, поскольку длина строки не должна превышать символов или полей LINE_MAX, включая символ новой строки, произвольное количество полей никогда не может быть частью реального условия этого решения.
Да, очень глупое решение, но единственное, которое соответствует критериям, я думаю.
Это не использует sedили, awkно это также не использует cut, так что я не совсем уверен, если он квалифицируется как ответ на вопрос в качестве его формулировки.
Это не очень хорошо работает, если обрабатывать входные строки, которые могут содержать косую черту. Обходной путь для такой ситуации - заменить косую черту другим символом, который, как вы знаете, не является частью допустимой входной строки. Например, |символ pipe ( ) также не разрешен в именах файлов, поэтому это будет работать:
Если у вас есть файл с именем filelist.txt, который представляет собой список путей, например, следующий: c: /dir1/dir2/file1.h c: /dir1/dir2/dir3/file2.h
тогда вы можете сделать это: rev filelist.txt | cut -d "/" -f1 | оборот
Добавляем подход к этому старому вопросу просто для удовольствия:
$ cat input.file # file containing input that needs to be processed
a;b;c;d;e
1;2;3;4;5
no delimiter here
124;adsf;15454
foo;bar;is;null;info
$ cat tmp.sh # showing off the script to do the job#!/bin/bash
delim=';'while read -r line;dowhile[["$line"=~"$delim"]];do
line=$(cut -d"$delim"-f 2-<<<"$line")done
echo "$line"done< input.file
$ ./tmp.sh # output of above script/processed input file
e
5
no delimiter here
15454
info
Помимо bash, используется только разрез. Ну и эхо, наверное.
Мех, почему бы просто полностью не удалить cut и использовать только bash ... x], чтобы while read -r line; do echo ${line/*;}; done <input.fileполучить тот же результат.
Каффе Майерс
-1
Я понял, что если мы просто убедимся, что конечный разделитель существует, он работает. Так что в моем случае у меня есть запятые и пробелы. Я добавляю пробел в конце;
cut
команду :)? почему нет других команд Linux?sed
илиawk
:perl -pe 's/^.+\s+([^\s]+)$/$1/'
.cut
поддерживает то, чего нет. Но я подумал, что это было полезно, так как заставляет читателя обдумывать код, за которым легче следовать. Я хотел быстрый, простой способ использоватьcut
без необходимости использования нескольких синтаксисов дляawk
,grep
,sed
и т.д. ,rev
что сделал трюк; очень элегантно, и то, что я никогда не рассматривал (даже если неуклюжий для других ситуаций). Мне также понравилось читать другие подходы из других ответов.find | cut -d. -f<last>
как и естественная склонностьОтветы:
Вы можете попробовать что-то вроде этого:
объяснение
rev
меняет "maps.google.com" наmoc.elgoog.spam
cut
использует точку (т. е. «.») в качестве разделителя и выбирает первое поле, котороеmoc
com
источник
cut
но это безsed
или. Такawk
что думают OP?rev
потом.rev
отличный идеал!Используйте расширение параметра. Это намного эффективнее, чем любая другая внешняя команда
cut
(илиgrep
) включена.Смотрите BashFAQ # 100 для ознакомления с нативной обработкой строк в bash.
источник
while IFS= read -ra array_var; do :;done <(cmd)
обработать несколько строк. Но для большого файла rev | cut | rev, вероятно, быстрее! (И, конечно, awk будет быстрее, чем это.)bash
скрипта (при условии, что вы уже используетеbash
скрипт). Не нужно называть что-либо внешним.rev
является специфическим для любой ОС вы используете , что обеспечивает его - это не стандартизировано во всех системах UNIX. Смотрите список глав для раздела POSIX по командам и утилитам - его там нет. И на самом деле не${var##prefix_pattern}
относится к bash; он соответствует стандарту POSIX sh , см. конец раздела 2.6.2 (связанный), поэтому в отличие от него он всегда доступен в любой совместимой оболочке.rev
Это невозможно, используя просто
cut
. Вот способ использованияgrep
:Замените запятую для других разделителей.
источник
grep -o '^.*,'
rev
добавить проблему многобайтовых символов Unicode в моем случае.sed 's/^.*,//'
который заменяет все символы до и включая последнюю запятую на пустую строку.Без awk? ... Но это так просто с awk:
AWK - намного более мощный инструмент, чтобы иметь в своем кармане. -F если для разделителя полей NF - количество полей (также обозначает индекс последнего)
источник
cut
для достижения конечного результата ОП аналогично использованию ложки для «нарезки» стейка (каламбур предназначен :)).awk
это нож для стейка.echo
которое может замедлить работу скрипта для длинных файловawk -F. '{print $NF}' <<< 'maps.google.com'
.Есть несколько способов. Вы можете использовать это тоже.
Очевидно, что ввод пробела для команды tr должен быть заменен нужным разделителем.
источник
Это единственное решение, которое можно использовать только для вырезания:
Используя это решение, количество полей действительно может быть неизвестно и время от времени изменяться. Однако, поскольку длина строки не должна превышать символов или полей LINE_MAX, включая символ новой строки, произвольное количество полей никогда не может быть частью реального условия этого решения.
Да, очень глупое решение, но единственное, которое соответствует критериям, я думаю.
источник
cut -f2-
в цикле до тех пор, пока выход больше не изменится.Если ваша входная строка не содержит прямой косой черты, вы можете использовать
basename
и подоболочку:Это не использует
sed
или,awk
но это также не используетcut
, так что я не совсем уверен, если он квалифицируется как ответ на вопрос в качестве его формулировки.Это не очень хорошо работает, если обрабатывать входные строки, которые могут содержать косую черту. Обходной путь для такой ситуации - заменить косую черту другим символом, который, как вы знаете, не является частью допустимой входной строки. Например,
|
символ pipe ( ) также не разрешен в именах файлов, поэтому это будет работать:источник
следующее реализует предложение друга
источник
echo
это работало надежно и надежно. См stackoverflow.com/questions/10067266/...Если у вас есть файл с именем filelist.txt, который представляет собой список путей, например, следующий: c: /dir1/dir2/file1.h c: /dir1/dir2/dir3/file2.h
тогда вы можете сделать это: rev filelist.txt | cut -d "/" -f1 | оборот
источник
Добавляем подход к этому старому вопросу просто для удовольствия:
Помимо bash, используется только разрез. Ну и эхо, наверное.
источник
while read -r line; do echo ${line/*;}; done <input.file
получить тот же результат.Я понял, что если мы просто убедимся, что конечный разделитель существует, он работает. Так что в моем случае у меня есть запятые и пробелы. Я добавляю пробел в конце;
источник
ans="a, b, c"
выдаетb
, что не соответствует требованиям «количество полей неизвестно или изменяется с каждой строкой» .