Чи є якась перевага у визначенні "./" в циклі for для використання глобула?


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.

Як зауважив steeldriver, "шаблон використання" префіксації макетів за допомогою ./корисний для обробки імен з провідними тире в оболонці bash . Це не впливає на розширення підстановки / назви файлів, але робить його більш безпечним / легшим в обробленні імен файлів, коли ви посилаєтесь на них, якщо вони починаються з символів, які ці програми можуть неправильно трактувати як параметри. Наприклад:

# 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 кращий за відлуння? з цієї причини та ін. Інші утиліти отримають інші параметри, тому краще представити назви комунальних послуг максимально безпечно. Якщо ви не префіксуєте підстановку для "втечі" імені файлів, вам доведеться "захищати" свої утиліти іншими способами; одне поширене - сигналізувати про закінчення варіантів --, наприклад:

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

... який надійно передасть -nім'я файлу mv(як видно з set -x):

mv -- -n backup/-n
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.