Bagaimana cara mendapatkan daftar file dalam direktori dalam skrip shell?


159

Saya mencoba untuk mendapatkan isi direktori menggunakan skrip shell.

Skrip saya adalah:

for entry in `ls $search_dir`; do
    echo $entry
done

di mana $search_dirjalur relatif. Namun, $search_dirberisi banyak file dengan spasi putih dalam namanya. Dalam hal ini, skrip ini tidak berjalan seperti yang diharapkan.

Saya tahu saya bisa menggunakan for entry in *, tetapi itu hanya akan berfungsi untuk direktori saya saat ini.

Saya tahu saya dapat mengubah ke direktori itu, gunakan for entry in *kemudian ubah kembali, tetapi situasi khusus saya mencegah saya melakukan itu.

Saya memiliki dua jalur relatif $search_dirdan $work_dir, dan saya harus mengerjakan keduanya secara bersamaan, membacanya membuat / menghapus file di dalamnya dll.

Jadi apa yang harus saya lakukan sekarang?

PS: Saya menggunakan bash.

Jawaban:


274
for entry in "$search_dir"/*
do
  echo "$entry"
done

4
Bisakah Anda jelaskan mengapa for entry in "$search_dir/*"tidak berhasil? Mengapa kita perlu menempatkan di /*luar tanda kutip?
mrgloom

6
@ mrgloom: Karena Anda harus membiarkan shell glob wildcard.
Ignacio Vazquez-Abrams

tidak findakan lebih cepat?
Alexej Magura

4
Solusinya memberikan jalan penuh. Bagaimana jika saya hanya ingin daftar apa yang ada di direktori saat ini?
ThatsRightJack

1
@mrgloom jika Anda ingin melakukannya Anda dapat mencapainya denganfor entry in "${search_dir}/*"
funilrys

28

Jawaban lain di sini luar biasa dan menjawab pertanyaan Anda, tetapi ini adalah hasil google teratas untuk "bash dapatkan daftar file dalam direktori", (yang saya cari untuk menyimpan daftar file) jadi saya pikir saya akan memposting jawaban untuk masalah itu:

ls $search_path > filename.txt

Jika Anda hanya menginginkan jenis tertentu (mis. File .txt):

ls $search_path | grep *.txt > filename.txt

Perhatikan bahwa $ search_path adalah opsional; ls> filename.txt akan melakukan direktori saat ini.


Tidak perlu menggunakan grep untuk mendapatkan hanya file .txt: `ls $ search_path / *. Txt> filename.txt '. Tetapi yang lebih penting, seseorang tidak harus menggunakan output dari perintah ls untuk mengurai nama file.
Victor Zamanian

1
@ Viktoramanian, dapatkah Anda menjelaskan mengapa kami tidak harus menggunakan output lsuntuk mengurai nama file? Belum pernah mendengar ini sebelumnya.
samurai_jane

1
@samurai_jane Ada banyak tautan untuk diberikan terkait topik ini, tapi inilah satu hasil pencarian pertama: mywiki.wooledge.org/ParsingLs . Saya bahkan melihat pertanyaan di sini di SO mengklaim alasan untuk tidak menguraikan output ls adalah BS dan sangat rumit tentang hal itu. Tetapi jawaban / jawaban masih mengklaim itu adalah ide yang buruk. Silahkan lihat: unix.stackexchange.com/questions/128985/…
Victor Zamanian

26

Ini adalah cara untuk melakukannya di mana sintaksinya lebih mudah bagi saya untuk mengerti:

yourfilenames=`ls ./*.txt`
for eachfile in $yourfilenames
do
   echo $eachfile
done

./adalah direktori aktif saat ini tetapi bisa diganti dengan jalur
*.txtapa saja mengembalikan apa pun.txt
Anda dapat memeriksa apa yang akan terdaftar dengan mudah dengan mengetikkan lsperintah langsung ke terminal.

Pada dasarnya, Anda membuat variabel yang yourfilenamesberisi semua yang dikembalikan oleh perintah daftar sebagai elemen yang terpisah, dan kemudian Anda mengulanginya. Loop membuat variabel sementara eachfileyang berisi elemen tunggal dari variabel yang dilaluinya, dalam hal ini nama file. Ini belum tentu lebih baik daripada jawaban yang lain, tetapi saya merasa intuitif karena saya sudah terbiasa dengan lsperintah dan sintaks for loop.


Ini berfungsi baik untuk skrip informal cepat atau satu baris, tetapi akan rusak jika nama file berisi baris baru, tidak seperti solusi berbasis global.
Soren Bjornstad

@SorenBjornstad terima kasih atas sarannya! Saya tidak tahu baris baru diizinkan dalam nama file - jenis file apa yang mungkin memilikinya? Seperti, apakah ini sesuatu yang biasa terjadi?
rrr

Baris baru dalam nama file jahat karena alasan ini dan sejauh yang saya tahu tidak ada alasan yang sah untuk menggunakannya. Saya sendiri belum pernah melihatnya di alam liar. Karena itu, sangat mungkin untuk membuat nama file dengan baris baru dengan jahat untuk mengeksploitasi ini. (Misalnya, bayangkan direktori yang berisi file A,, Bdan C. Anda membuat file yang dipanggil B\nCdan D, lalu memilih untuk menghapusnya. Perangkat lunak yang tidak menangani hak ini bisa berakhir dengan menghapus file yang sudah ada sebelumnya, B dan C bahkan jika Anda tidak memiliki izin untuk melakukan itu.)
Soren Bjornstad

19
for entry in "$search_dir"/* "$work_dir"/*
do
  if [ -f "$entry" ];then
    echo "$entry"
  fi
done

11
find "${search_dir}" "${work_dir}" -mindepth 1 -maxdepth 1 -type f -print0 | xargs -0 -I {} echo "{}"

1
Saya tahu ini cukup tua tetapi saya tidak bisa mendapatkan xargs -0 -i echo "{}"perintah terakhir , mau jelaskan sedikit? Khususnya apa yang -i echo "{}"dilakukan bagian itu? Saya juga membaca dari manhalaman yang -isudah usang sekarang dan kita harus menggunakan -Iinsted.
drkg4b

1
-ipengganti {}dengan arg.
Noel Yap

Terima kasih! Ini berguna, juga untuk yang berpikiran lambat seperti saya, saya pikir itu {}adalah string yang diganti dengan yang sesuai dengan findperintah.
drkg4b

3
mengapa Anda menggunakan xargs? secara default, findcetak apa yang ditemukannya ... Anda dapat menghapus semuanya -print0.
gniourf_gniourf

1
Melakukan itu tidak akan menangani entri file dengan spasi dengan baik.
Noel Yap

4
$ pwd; ls -l
/home/victoria/test
total 12
-rw-r--r-- 1 victoria victoria    0 Apr 23 11:31  a
-rw-r--r-- 1 victoria victoria    0 Apr 23 11:31  b
-rw-r--r-- 1 victoria victoria    0 Apr 23 11:31  c
-rw-r--r-- 1 victoria victoria    0 Apr 23 11:32 'c d'
-rw-r--r-- 1 victoria victoria    0 Apr 23 11:31  d
drwxr-xr-x 2 victoria victoria 4096 Apr 23 11:32  dir_a
drwxr-xr-x 2 victoria victoria 4096 Apr 23 11:32  dir_b
-rw-r--r-- 1 victoria victoria    0 Apr 23 11:32 'e; f'

$ find . -type f
./c
./b
./a
./d
./c d
./e; f

$ find . -type f | sed 's/^\.\///g' | sort
a
b
c
c d
d
e; f

$ find . -type f | sed 's/^\.\///g' | sort > tmp

$ cat tmp
a
b
c
c d
d
e; f

Variasi

$ pwd
/home/victoria

$ find $(pwd) -maxdepth 1 -type f -not -path '*/\.*' | sort
/home/victoria/new
/home/victoria/new1
/home/victoria/new2
/home/victoria/new3
/home/victoria/new3.md
/home/victoria/new.md
/home/victoria/package.json
/home/victoria/Untitled Document 1
/home/victoria/Untitled Document 2

$ find . -maxdepth 1 -type f -not -path '*/\.*' | sed 's/^\.\///g' | sort
new
new1
new2
new3
new3.md
new.md
package.json
Untitled Document 1
Untitled Document 2

Catatan:

  • . : folder saat ini
  • hapus -maxdepth 1untuk mencari secara rekursif
  • -type f: cari file, bukan direktori ( d)
  • -not -path '*/\.*' : jangan kembali .hidden_files
  • sed 's/^\.\///g': hapus yang diawali ./dari daftar hasil

0

Berikut cara lain untuk mendaftarkan file di dalam direktori (menggunakan alat yang berbeda, tidak seefisien beberapa jawaban lainnya).

cd "search_dir"
for [ z in `echo *` ]; do
    echo "$z"
done

echo *Keluarkan semua file dari direktori saat ini. The forLoop iterates atas setiap nama file dan mencetak ke stdout.

Selain itu, Jika mencari direktori di dalam direktori maka letakkan ini di dalam forloop:

if [ test -d $z ]; then
    echo "$z is a directory"
fi

test -d memeriksa apakah file tersebut adalah direktori.


0

Jawaban yang diterima tidak akan mengembalikan awalan file dengan a. Untuk melakukan itu gunakan

for entry in "$search_dir"/* "$search_dir"/.[!.]* "$search_dir"/..?*
do
  echo "$entry"
done

-1

Pada versi Linux saya bekerja dengan (x86_64 GNU / Linux) bekerja sebagai berikut:

for entry in "$search_dir"/*
do
  echo "$entry"
done

-1: Ini identik dengan jawaban yang diterima kecuali itu tidak mengutip variabel. Tidak mengutip $search_dirberarti rusak jika ada ruang dalam nama direktori. (Dalam hal ini Anda bisa lolos dengan tidak mengutip $entry, tetapi akan lebih baik untuk mengutipnya.)
Soren Bjornstad

Anda salah. Solusi saya tidak sama, bahkan ketika itu mirip dengan jawaban yang diterima. Dan itu BUKAN salah, itu berhasil. Inilah yang saya coba pada sistem unix yang berbeda, termasuk Mac OS, dan itu berhasil pada masing-masing sistem. File dengan kosong, bahkan ketika itu memiliki kosong dalam nama, ditampilkan dengan benar. search_dir =. untuk entri di $ search_dir / *; lakukan echo $ entry; selesai ./ aa aaa.txt ./add ./apm_tables.txt Anda dapat memilih solusi hanya ketika Anda dapat membuktikan bahwa solusi TIDAK BEKERJA atau menghasilkan hasil yang salah.
Andrushenko Alexander

Jika Anda membaca komentar saya sedikit lebih dekat, Anda akan melihat masalah dengan kosong pada nama direktori , bukan nama file . Itu berbeda dari masalah yang ditemui si penanya, tetapi itu tetap berarti kode tersebut dapat rusak secara tidak sengaja! Berikut ini adalah contoh dari apa yang tidak bekerja: mkdir "x y"; touch "x y/1.txt"; search_dir="x y"; for entry in $search_dir/*; do echo $entry; done. Pengulangan berjalan dua kali, sekali pencetakan xdan kedua kalinya y/*, yang mungkin bukan hasil yang diharapkan.
Soren Bjornstad

Dan saya menganggap variabel yang tidak dikutip dengan benar salah, yang merupakan alasan untuk downvote. Pertimbangkan kode ini untuk menghapus subdirektori dari direktori pencarian sementara meninggalkan file: search_dir="x y"; for entry in $search_dir/*; do if [ -d "$entry" ]; then rm -rf "$entry"; fi; done. Jika ada juga xdirektori di direktori saat ini, itu dihapus, hanya karena Anda tidak mengutip variabel Anda!
Soren Bjornstad

Nah, Anda selalu mengambil kode yang dibuat untuk satu tugas, sedikit mengubah tugas dan kode menjadi salah. Untuk pertanyaan yang diajukan solusi yang saya usulkan bekerja. Tapi ... sebagai pengembang saya harus setuju dengan argumen Anda: jika kita bisa membuat kode lebih kuat dan umum, kita harus melakukannya. Jadi saya akan menambahkan qoutes. Ini akan membuat jawaban saya identik dengan jawaban yang diberikan di atas, tetapi demi diskusi (yang mungkin berguna bagi seseorang) saya meninggalkan jawabannya juga.
Andrushenko Alexander

-1

Cukup masukkan perintah sederhana ini:

ls -d */

Bisakah Anda memberikan penjelasan @ Michael Sisko
Vipul

ls (daftar) -d (daftar hanya direktori) * / (dari pola apa pun, backslash membatasi daftar hanya untuk direktori).
Michael Sisko
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.