Есть ли какое-то преимущество в указании './' в цикле for с использованием glob?

10

У меня сложилось впечатление, что это может быть более безопасно использовать ./*.fastqпри поиске файлов, заканчивающихся на .fastq. Например, ./помешает захват файла .fastq. Это, очевидно, неправильно, как показано в примере ниже:

TMP_DIR=$(mktemp --directory)
mkdir -p ${TMP_DIR}
(cd ${TMP_DIR}
 touch {a,b,c,}.fastq
 ls -a
 echo ""

 echo "# match all:"
 for f in *.fastq ; do
     echo "${f}"
 done
 echo ""

 echo "# with ./:"
 for f in ./*.fastq ; do
     echo "${f}"
 done
)
rm -rf ${TMP_DIR}
.
..
a.fastq
b.fastq
c.fastq
.fastq

# match all:
a.fastq
b.fastq
c.fastq

# with ./:
./a.fastq
./b.fastq
./c.fastq

Ни то, *.fastqни другое не ./*.fastqсоответствует файлу .fastq. Итак, мне интересно, есть ли смысл использовать ./*.fastqздесь или ./*вообще?

Фредерик Маэ
источник
1
Обычно это ./*означает, что имена, начинающиеся с -, не рассматриваются как параметры.
Чарльз Даффи

Ответы:

15

Это изначально удивительное поведение с подстановочными знаками, так как описание для *подстановочного знака говорит:

Соответствует любой строке, включая пустую строку.

... пока вы не поймете, что период немного особенный, когда это первый символ имени файла. Вступительный текст 3.5.8 Filename Expansionговорит:

Когда шаблон используется для расширения имени файла, символ «.» в начале имени файла или сразу после слэша должен явно совпадать, если не установлен параметр оболочки dotglob.

«Шаблон использования» префикса с ./использованием подстановочных знаков полезен для обработки имен с начальным тире в оболочке bash , как прокомментировал Steeldriver. Он не влияет на расширение подстановочного знака / имени файла, но делает более безопасным / легче обрабатывать имена файлов, когда вы ссылаетесь на них, если они начинаются с символов, которые эти программы могут неправильно интерпретировать как параметры. Например:

# I want a file named `-n`
$ touch -n
touch: invalid option -- 'n'
Try 'touch --help' for more information.
$ touch -- -n
### ok
$ touch ./-n
### ok

... и теперь, когда у меня есть файл с именем -n, если мне случится зациклить его с подстановочным знаком:

for file in *n
do
  echo "$file"
done

... я не получаю вывод!

Но если я добавлю префикс подстановки ./,

for file in ./*n
do
  echo "$file"
done
./-n

... Я вижу имя файла.

Это простой пример для демонстрационных целей; см. также Почему printf лучше, чем echo? по этой причине и другие. Другие утилиты будут отключены другими опциями, поэтому лучше представить файлы утилит как можно более безопасно. Если вы не ставите префикс подстановки для «экранирования» имен файлов, вам придется «защищать» свои утилиты другими способами; Одним из распространенных является сигнал об окончании опций --, например:

for file in *n
do
  mv -- "$file" backup/"$file"
done

... который безопасно передаст -nимя файла mv(как показано ниже set -x):

mv -- -n backup/-n
Джефф Шаллер
источник