TL;DR: если вам не нравится ls
, даже если это НЕ специфическая команда (объяснение ниже), используйте arr=(); for foo in * [!*]*; do [[ $foo == test* ]] && arr+=("$foo"); done
. По сути это arr=list_files.filter((i) -> (i.glob_match('test*')));
как вы можете написать на некоторых других языках.
Но если вы будете читать дальше, то узнаете, что ls
- это хорошо, и эти проверки следует пропустить, используя прямое присваивание массива, например arr=(test*)
(mikeserv заставил меня понять, что я действительно должен сказать это первым).
Как и другие упоминают в комментариях, Unix shell просто передает текстовые потоки, а не пакеты объектов. И поскольку мир Unix позволяет гораздо больше вещей в именах файлов и во многих других пространствах, чем Windows, только границы слов оболочки безопасны. Для таких вещей, как имена файлов, где \0
, к счастью, не разрешено, вы можете использовать его и в потоках.
grep
и друзья продолжают служить в качестве основного текстового фильтра. Он принимает строки из stdin или файлов, сравнивает с заданным regex и выдает совпавшие (или обратные, -v
) строки или части (-o
) как stdout, еще один поток, который все еще небезопасно использовать.
Это работает для текста, разделенного новыми строками, такого как большинство кодов и стихов, но не для имен файлов. Имена файлов могут содержать новые строки, и grep
может увидеть две отдельные строки для одного файла из ls
.
В оболочках UNIX подстановочные знаки обрабатываются оболочкой, а не целевой программой. Это делает вещи более последовательными, а также вызывает путаницу, которая заставляет вас думать, что часть test*
имеет отношение к ls
.
Предположим, у нас есть файлы test1
, test2
, test3
, ls только кажется, что его вызвали вот так:
ls test1 test2 test3
Он практически ничего не знает о том, что вы с ним сделали.
Внутри, test*
расширяется до shell words. И поскольку у нас есть конструкция for varname in [word-list]; do [commands]; done
, мы можем делать вещи вроде этой:
for i in *; do
if i matches the pattern; then
do something
fi # that marks endif
done
И в bash есть одна вещь, [[
], которая выполняет сопоставление шаблонов. Для данной констукции [[ lhs == rhs ]]
, bash проверяет, совпадает ли lhs
с шаблоном на rhs
. В нашем случае мы можем использовать [[ $i == test* ]]
для того, чтобы i совпал с шаблоном
. Это недоступно в минимальной оболочке POSIX, для этого используйте case
.
И нам нужно добавить некоторые действия, чтобы сделать что-то
. В bash есть массивы:
# Arrays doesn't exist in POSIX standard too.
a=() # an empty array, since bash is weak-typed this doesn't mean anything
b=(foo bar baz) # array are assigned with, well, list-of-words.
for i in *; do
if [ $i == test* ]]; then
a+=("$i") # quoting avoids some word-splitting and you know what += is
fi # that marks endif
done
# and here do something to your lonely array, like those described in
# gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html
Еще один момент. В системах Unix по соглашению имена файлов, начинающиеся с .
обозначают скрытый файл, и *
не будет их включать. .*
добавляет их явно, но .
означает текущий dir, а ...
означает basedir (тот же, что и в windows), поэтому вы хотите избавиться от них. Использование .[!.]*
работает, так как оно означает точку, символ, который не является точкой, и любое число, включая ноль символов. Это не имеет ничего общего с вашим test*
, поскольку test
не начинается с .
.
А для множественного шаблона 'or' мы можем использовать extglob
(сначала запустите shopt -s extglob
) вещь @(patt1|patt2)
, или мы можем обернуть все это дело case
, где разрешены множественные шаблоны, ...
Но зачем вам это нужно? Просто используйте a=(test*)
. test*
даст вам список слов, если есть совпадение. Для нескольких шаблонов используйте a=(test* tset*)
.
Если glob не совпадает ни с чем, он остается в списке слов как сам шаблон glob. Это хорошо для ленивых пользователей shells, но не для серьезных скриптеров вроде нас.
К счастью, в bash есть shopt
под названием nullglob
, который не возвращает шаблон glob обратно. Просто используйте shopt -s nullglob
, чтобы сначала включить его. Если вы хотите, чтобы он был переносимым среди других POSIX-оболочек, что ж, давайте вернемся к for-and-case-фильтрации.
ls
решенияВ следующем --
добавлено на случай, если то, что вы глобализируете, не test*
, а *test*
, и вы можете получить какое-то имя файла вроде -test123
и быть распознанным как некоторые ls
опции. --
отмечает конец опций по соглашению.
# So what you need is globbing:
echo test*
# But those are not clear enough since echo only adds spaces between them. Use newlines:
printf '%s\n' test*
# But our screen doesn't have so many lines. Ah, yes, ls can make it into columns:
ls -- test*
# But it lists the contents of the directory test233/. Let's ask it not to:
ls -d -- test*
# Oh, good enough, let's add some color and some pretty type indicator:
ls -dF --color=auto -- test*
Так что для вашего простого вопроса это выглядит следующим образом: ls -d test*
. Но это НЕ для одной команды; мы используем ls
только для красивой печати.
Нет. Некоторые программы пытались заставить людей думать, что их безопасно использовать, добавляя/используя делимитатор \0
, например find -print0
и xargs -0
. К сожалению, это требует некоторых хаков, чтобы позволить оболочкам принимать \0
, так что...
И во многих оболочках все еще есть лучшее решение для globbing. find
рекурсивно ходит по каталогу и условно печатает найденные имена файлов, и часто используется как способ рекурсивного перечисления файлов. В bash мы имеем следующее:
shopt -s globstar
for i in **; do
try-some-test || continue
do-something
done
Что делает работу просто отлично.
Но bash
не обеспечивает всего, например, у него нет аккуратных параллельных команд, и он никогда не работает так же быстро, как нативный код. Поэтому люди используют другие программы, такие как parallel
. Поскольку у нас есть \0
, что ж, это не так уж плохо, и мы можем использовать find -print0
для его подачи.
Просто используйте if not exists
в своих запросах. Например:
create if not exists user '${test}'@'localhost' identified by '${psw}';
илиcreate database if not exists ${test};
Ваша версия mysql может отличаться, обратитесь к правильной версии. Но больше информации можно найти на: