Czy jest jakaś zaleta w określaniu „./” w pętli for za pomocą glob?

10

Miałem wrażenie, że korzystanie z niej ./*.fastqprzy wyszukiwaniu plików z końcówką może być bezpieczniejsze .fastq. Na przykład ./zapobiegnie przechwytywaniu pliku .fastq. Jest to oczywiście niewłaściwe, jak pokazano w poniższym przykładzie:

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

Ani *.fastqteż nie ./*.fastqpasuje do pliku .fastq. Zastanawiam się teraz, czy jest jakiś sens ./*.fastqtutaj, czy ./*ogólnie?

Frédéric Mahé
źródło
1
Zazwyczaj chodzi o ./*to, że zapewnia, że ​​nazwy zaczynające się od -nie są traktowane jako opcje.
Charles Duffy,

Odpowiedzi:

15

Jest to początkowo zaskakujące zachowanie symboli wieloznacznych, ponieważ opis *znaku wieloznacznego brzmi:

Dopasowuje dowolny ciąg, w tym ciąg zerowy.

... dopóki nie zdasz sobie sprawy, że kropka jest nieco wyjątkowa, gdy jest to pierwszy znak nazwy pliku. Tekst wprowadzający 3.5.8 Filename Expansionmówi:

Gdy wzorzec jest używany do interpretacji nazwy pliku, znak „.” na początku nazwy pliku lub bezpośrednio po ukośniku należy jawnie dopasować, chyba że ustawiono opcję powłoki dotglob.

„Wzorzec użycia” poprzedzania symboli wieloznacznych za pomocą ./jest użyteczny do obsługi nazw z wiodącym myślnikiem w powłoce bash , jak komentował Steeldriver. Nie ma to wpływu na rozszerzenie symbolu wieloznacznego / nazwy pliku, ale sprawia, że ​​bezpieczniej / łatwiej jest obsługiwać nazwy plików, gdy się do nich odwołujesz, jeśli zaczynają się od znaków, które te programy mogą błędnie interpretować jako opcje. Na przykład:

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

... a teraz, gdy mam plik o nazwie -n, jeśli przypadkiem zapętlę go za pomocą symbolu wieloznacznego:

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

... nie mam wyjścia!

Ale jeśli poprzedzę znak wieloznaczny ./,

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

... widzę nazwę pliku.

Jest to prosty przykład do celów demonstracyjnych; zobacz także Dlaczego printf jest lepszy niż echo? z tego i innych powodów. Inne narzędzia będą wyzwalane przez inne opcje, więc lepiej przedstawić nazwy plików narzędziom tak bezpiecznie, jak to możliwe. Jeśli nie użyjesz wieloznacznika do „ucieczki” nazw plików, będziesz musiał „chronić” swoje narzędzia na inne sposoby; jedną wspólną jest zasygnalizowanie końca opcji --, na przykład:

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

... który bezpiecznie przekaże -nnazwę pliku do mv(jak pokazano poniżej set -x):

mv -- -n backup/-n
Jeff Schaller
źródło