Boşlukları ve joker karakterleri olan yolları olan dizelerde Bash komut dosyası hatası


25

Bash'in yazılmasının temellerini bulmakta sorun yaşıyorum. İşte şimdiye kadar sahip olduğum şey:

#!/bin/bash
FILES="/home/john/my directory/*.txt"

for f in "${FILES}"
do
  echo "${f}"
done

Tek yapmak istediğim .txtbir fordöngüdeki tüm dosyaları listelemek, böylece onlarla bir şeyler yapabilirim. Fakat içindeki my directoryve yıldızdaki boşluklar *.txtgüzelce oynamıyor. Çift tırnaklı ve tırnaksız, değişken isimler üzerinde küme parantezi olan ve olmayanlar kullanmaya çalıştım ve hala tüm .txtdosyaları yazdıramıyorum .

Bu çok basit bir şey, ama hala mücadele ediyorum çünkü yorgunum ve doğru düşünemiyorum.

Neyi yanlış yapıyorum?

FILES'imde boşluk veya yıldız işareti yoksa, yukarıdaki betiği başarıyla uygulayabildim ... Çalışması için çift tırnaklı ve köşeli ayraç kullanımıyla veya onsuz denemek zorunda kaldım. Fakat hem boşluklara hem de yıldıza sahip olduğum an, her şeyi mahvetti.

Yanıtlar:


33

Tırnak işaretleri içinde, *bir dosya listesine genişletilmez. Böyle bir joker karakteri başarılı bir şekilde kullanmak için, tırnak işaretleri dışında olması gerekir.

Joker karakter genişlemiş olsa bile, ifade "${FILES}"bir dosya listesi değil, tek bir dize ile sonuçlanır.

İşe yarayacak bir yaklaşım şöyle olurdu:

#!/bin/bash
DIR="/home/john/my directory/"
for f in "$DIR"/*.txt
do
  echo "${f}"
done

Yukarıda, boşluklu veya diğer zor karakterli dosya adları doğru şekilde ele alınacaktır.

Daha gelişmiş bir yaklaşım bash dizilerini kullanabilir:

#!/bin/bash
FILES=("/home/john/my directory/"*.txt)
for f in "${FILES[@]}"
do
  echo "${f}"
done

Bu durumda, FILESbir dosya adı dizisidir. Tanımı çevreleyen parenler onu bir dizi yapar. Bunun *tırnak işaretleri dışında olduğunu unutmayın . Yapı "${FILES[@]}"özel bir durumdur: her dizenin dosya isimlerinden biri olduğu bir dizi dizine genişleyecektir. Boşluklu veya zor karakterler içeren dosya adları doğru şekilde ele alınacaktır.


1
Bu harika çalıştı
John

İşlevlerin etrafında böyle bir yoldan geçiyorsanız, değişkeni daha büyük bir dizenin parçası olarak birleştirmek yerine , kendi başına alıntı yaptığınızdan emin olmanız gerekir : for f in "$DIR"/*.txt= fine for f in "$DIR/*.txt"= breaks
pospi

7

John1024 tarafından gösterildiği gibi dizileri kullanmak çok daha anlamlı olsa da, burada split + glob operatörünü de kullanabilirsiniz (skaler değişkeni işaretsiz bırakarak).

Bu operatörün yalnızca glob bölümünü istediğiniz için, split parçasını devre dışı bırakmanız gerekir :

#! /bin/sh -
# that also works in any sh, so you don't even need to have or use bash

file_pattern="/home/john/my directory/*.txt"
# all uppercase variables should be reserved for environment variables

IFS='' # disable splitting

for f in $file_pattern # here we're not quoting the variable so
                       # we're invoking the split+glob operator.
do
  printf '%s\n' "$f" # avoid the non-reliable, non-portable "echo"
done

0

Yapabilecekleriniz yalnızca joker karakterleri tırnak işaretleri dışında bırakmaktır.
Gibi bir şey:
Bir için "boşluklarla dosyaları" * "txt"
do
işlenirken
yapılan
joker kendileri mekanlara genişletmek, o zaman kullanım ls listesini oluşturmak için -l sevmiyor, bu hat yaklaşımı başına bir dosyayı kullanmak gerekir dosyaları ve her dosyayı almak için bash read kullanın.


-1

Dosyaların sette sürecine istediğinizde, Yani önce böyle gibi işlemini başlatmak, kişilerin adlarına boşluk veya başka günah kodu olacak olabilir, düşünün for loopveya find commandayarlamak IFS bash env variableiçin:

IFS=$(echo -en "\n\b")
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.