У меня есть файл, который содержит имена каталогов:
my_list.txt
:
/tmp
/var/tmp
Я хотел бы проверить в Bash, прежде чем я добавлю имя каталога, если это имя уже существует в файле.
У меня есть файл, который содержит имена каталогов:
my_list.txt
:
/tmp
/var/tmp
Я хотел бы проверить в Bash, прежде чем я добавлю имя каталога, если это имя уже существует в файле.
Ответы:
grep -Fxq "$FILENAME" my_list.txt
Статус выхода равен 0 (true), если имя найдено, 1 (false), если нет, поэтому:
if grep -Fxq "$FILENAME" my_list.txt
then
# code if found
else
# code if not found
fi
Вот соответствующие разделы справочной страницы дляgrep
:
grep [options] PATTERN [FILE...]
-F
,--fixed-strings
Интерпретировать PATTERN как список фиксированных строк, разделенных символами новой строки, любой из которых должен соответствовать.
-x
,--line-regexp
Выберите только те совпадения, которые точно соответствуют всей строке.
-q
,--quiet
,--silent
Тихо; не пишите ничего в стандартный вывод. Выйдите немедленно с нулевым статусом, если найдено какое-либо совпадение, даже если обнаружена ошибка. Также смотрите опцию
-s
или--no-messages
.
Как справедливо указано в комментариях, вышеупомянутый подход молча обрабатывает случаи ошибок, как если бы строка была найдена. Если вы хотите обрабатывать ошибки другим способом, вам придется пропустить этот -q
параметр и обнаруживать ошибки на основе состояния выхода:
Обычно статус выхода равен 0, если выбранные строки найдены, и 1 в противном случае. Но состояние выхода равно 2, если произошла ошибка, если не используется опция
-q
или--quiet
или--silent
и не найдена выбранная строка. Однако обратите внимание, что POSIX обязывает только для таких программ, какgrep
,cmp
иdiff
что состояние выхода в случае ошибки должно быть больше 1; поэтому для переносимости целесообразно использовать логику, которая проверяет это общее условие, вместо строгого равенства с 2.
Чтобы подавить нормальный вывод с grep
, вы можете перенаправить его на /dev/null
. Обратите внимание, что стандартная ошибка остается ненаправленной, поэтому любые сообщения об ошибках, которые grep
могут быть напечатаны, будут появляться на консоли, как вы, вероятно, захотите.
Для обработки трех случаев мы можем использовать case
инструкцию:
case `grep -Fx "$FILENAME" "$LIST" >/dev/null; echo $?` in
0)
# code if found
;;
1)
# code if not found
;;
*)
# code if an error occurred
;;
esac
$?
. Вы также можете использовать команду grep вместе с if
оператором (как показано в обновленном ответе).
grep -Fqx "$FILENAME"
и вам не нужно беспокоиться о регулярных выражениях в содержимом переменных, и вам не придется использовать их в строке поиска.
-q / --silent
это нужно? Это ложно говорит "все хорошо", чтобы bash, даже если происходит ошибка. Если я правильно понял. Кажется некорректной концепцией для этого случая.
Относительно следующего решения:
grep -Fxq "$FILENAME" my_list.txt
Если вам интересно (как я это сделал), что -Fxq
означает на простом английском:
F
: Влияет на интерпретацию PATTERN (фиксированная строка вместо регулярного выражения)x
: Соответствовать всей линииq
: Тссс ... минимальная печатьИз файла man:
-F, --fixed-strings
Interpret PATTERN as a list of fixed strings, separated by newlines, any of which is to be matched.
(-F is specified by POSIX.)
-x, --line-regexp
Select only those matches that exactly match the whole line. (-x is specified by POSIX.)
-q, --quiet, --silent
Quiet; do not write anything to standard output. Exit immediately with zero status if any match is
found, even if an error was detected. Also see the -s or --no-messages option. (-q is specified by
POSIX.)
Три метода в моей голове:
1) Короткий тест для имени в пути (я не уверен, что это может быть ваш случай)
ls -a "path" | grep "name"
2) Краткий тест для строки в файле
grep -R "string" "filepath"
3) Более длинный скрипт bash с использованием регулярных выражений:
#!/bin/bash
declare file="content.txt"
declare regex="\s+string\s+"
declare file_content=$( cat "${file}" )
if [[ " $file_content " =~ $regex ]] # please note the space before and after the file content
then
echo "found"
else
echo "not found"
fi
exit
Это должно быть быстрее, если вам нужно протестировать несколько строк в содержимом файла, используя цикл, например, изменить регулярное выражение в любом цикле.
Более простой способ:
if grep "$filename" my_list.txt > /dev/null
then
... found
else
... not found
fi
Подсказка: отправьте, /dev/null
если хотите получить статус выхода команды, но не вывод.
-q
же самое, что и --quiet
:)
-q
также лучший ответ здесь, и это четвертое место. нет справедливости в этом мире.
Самый простой и простой способ будет:
isInFile=$(cat file.txt | grep -c "string")
if [ $isInFile -eq 0 ]; then
#string not contained in file
else
#string is in file at least once
fi
grep -c вернет счетчик того, сколько раз строка встречается в файле.
Если я правильно понял ваш вопрос, это должно сделать то, что вам нужно.
В одной строке :check="/tmp/newdirectory"; [[ -n $(grep "^$check\$" my_list.txt) ]] && echo "dir already listed" || echo "$check" >> my_list.txt
grep -q
и вызывать grep напрямую, if
как это делает Томас в своем ответе. Кроме того, вопрос не включал проверку существования каталога до его добавления в список (в конце концов, это может быть список удаленных каталогов).
grep -E "(string)" /path/to/file || echo "no match found"
-E опция заставляет grep использовать регулярные выражения
Решение @ Thomas почему-то не сработало, но у меня была более длинная строка со специальными символами и пробелами, поэтому я просто изменил параметры следующим образом:
if grep -Fxq 'string you want to find' "/path/to/file"; then
echo "Found"
else
echo "Not found"
fi
Надеюсь, это поможет кому-то
Решение без grep, работает для меня:
MY_LIST=$( cat /path/to/my_list.txt )
if [[ "${MY_LIST}" == *"${NEW_DIRECTORY_NAME}"* ]]; then
echo "It's there!"
else
echo "its not there"
fi
на основании: https://stackoverflow.com/a/229606/3306354
grep -q
Описанный в принятом ответе наиболее эффективный подход.
grep -Fxq "String to be found" | ls -a
if grep -q "$Filename$" my_list.txt
then
echo "exist"
else
echo "not exist"
fi