Apakah ada keuntungan dalam menentukan './' dalam for for loop menggunakan glob?

10

Saya mendapat kesan bahwa itu bisa lebih aman untuk digunakan ./*.fastqketika mencari file yang diakhiri .fastq. Misalnya, ./akan mencegah pengambilan file .fastq. Ini jelas salah, seperti yang ditunjukkan pada contoh di bawah ini:

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

Baik *.fastqatau ./*.fastqmencocokkan file .fastq. Jadi saya ingin tahu sekarang, apakah ada gunanya menggunakan di ./*.fastqsini, atau ./*secara umum?

Frédéric Mahé
sumber
1
Hal yang biasa dilakukan ./*adalah memastikan bahwa nama yang dimulai dengan -tidak diperlakukan sebagai opsi.
Charles Duffy

Jawaban:

15

Itu awalnya mengejutkan perilaku wildcard, karena deskripsi untuk *karakter wildcard mengatakan:

Cocok dengan sembarang string, termasuk string nol.

... sampai Anda menyadari bahwa periode itu sedikit istimewa ketika itu adalah karakter pertama dari sebuah nama file. Teks pengantar di 3.5.8 Filename Expansionmengatakannya:

Saat pola digunakan untuk ekspansi nama file, karakter '.' di awal nama file atau segera setelah slash harus dicocokkan secara eksplisit, kecuali opsi shell dotglob diatur.

"Pola penggunaan" dari awalan wildcard dengan ./berguna untuk Menangani nama dengan dasbor terdepan dalam bash shell , seperti komentar steeldriver. Ini tidak berpengaruh pada ekspansi wildcard / nama file, tetapi membuatnya lebih aman / lebih mudah untuk menangani nama file ketika Anda merujuknya, jika mereka mulai dengan karakter yang mungkin disalahartikan oleh program-program tersebut sebagai opsi. Sebagai contoh:

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

... dan sekarang saya memiliki file yang bernama -n, jika kebetulan saya memutarnya dengan wildcard:

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

... Saya tidak mendapatkan hasil!

Tetapi jika saya awali wildcard dengan ./,

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

... Saya melihat nama file.

Ini adalah contoh sederhana untuk tujuan demonstrasi; lihat juga Mengapa printf lebih baik daripada gema? untuk alasan ini dan lainnya. Utilitas lain akan tersandung oleh opsi lain, jadi lebih baik menghadirkan nama file ke utilitas seaman mungkin. Jika Anda tidak awalan wildcard untuk "melarikan diri" nama file, Anda harus "melindungi" utilitas Anda dengan cara lain; satu yang umum adalah untuk menandai akhir dari opsi dengan --, misalnya:

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

... yang akan meneruskan -nnama file dengan aman mv(seperti yang terlihat di bawah set -x):

mv -- -n backup/-n
Jeff Schaller
sumber