Jawaban ini memiliki solusi untuk semua jenis file. Dengan baris atau spasi baru.
Ada solusi untuk bash baru-baru ini serta bash kuno dan bahkan kerang posix lama.
Pohon yang tercantum di bawah dalam jawaban ini [1] digunakan untuk pengujian.
Pilih
Mudah select
untuk bekerja dengan array:
$ dir='deep/inside/a/dir'
$ arr=( "$dir"/* )
$ select var in "${arr[@]}"; do echo "$var"; break; done
Atau dengan parameter posisi:
$ set -- "$dir"/*
$ select var; do echo "$var"; break; done
Jadi, satu-satunya masalah sebenarnya adalah mendapatkan "daftar file" (dibatasi dengan benar) di dalam array atau di dalam Parameter Posisi. Teruslah membaca.
pesta
Saya tidak melihat masalah yang Anda laporkan dengan bash. Bash dapat mencari di dalam direktori yang diberikan:
$ dir='deep/inside/a/dir'
$ printf '<%s>\n' "$dir"/*
<deep/inside/a/dir/directory>
<deep/inside/a/dir/file>
<deep/inside/a/dir/file name>
<deep/inside/a/dir/file with a
newline>
<deep/inside/a/dir/zz last file>
Atau, jika Anda menyukai loop:
$ set -- "$dir"/*
$ for f; do printf '<%s>\n' "$f"; done
<deep/inside/a/dir/directory>
<deep/inside/a/dir/file>
<deep/inside/a/dir/file name>
<deep/inside/a/dir/file with a
newline>
<deep/inside/a/dir/zz last file>
Perhatikan bahwa sintaks di atas akan bekerja dengan benar dengan shell (wajar) (setidaknya csh).
Satu-satunya batasan yang dimiliki sintaks di atas adalah turun ke direktori lain.
Tapi bash bisa melakukan itu:
$ shopt -s globstar
$ set -- "$dir"/**/*
$ for f; do printf '<%s>\n' "$f"; done
<deep/inside/a/dir/directory>
<deep/inside/a/dir/directory/file>
<deep/inside/a/dir/directory/file name>
<deep/inside/a/dir/directory/file with a
newline>
<deep/inside/a/dir/directory/zz last file>
<deep/inside/a/dir/file>
<deep/inside/a/dir/file name>
<deep/inside/a/dir/file with a
newline>
<deep/inside/a/dir/zz last file>
Untuk memilih hanya beberapa file (seperti yang berakhir pada file) cukup ganti *:
$ set -- "$dir"/**/*file
$ printf '<%s>\n' "$@"
<deep/inside/a/dir/directory/file>
<deep/inside/a/dir/directory/zz last file>
<deep/inside/a/dir/file>
<deep/inside/a/dir/zz last file>
kuat
Ketika Anda menempatkan "ruang- aman " di judul, saya akan menganggap bahwa apa yang Anda maksudkan adalah " kuat ".
Cara paling sederhana untuk menjadi kuat tentang spasi (atau baris baru) adalah menolak pemrosesan input yang memiliki spasi (atau baris baru). Cara yang sangat sederhana untuk melakukan ini di shell adalah keluar dengan kesalahan jika ada nama file yang mengembang dengan spasi. Ada beberapa cara untuk melakukan ini, tetapi yang paling ringkas (dan posix) (tetapi terbatas pada satu isi direktori, termasuk nama direktori dan menghindari dot-file) adalah:
$ set -- "$dir"/file* # read the directory
$ a="$(printf '%s' "$@" x)" # make it a long string
$ [ "$a" = "${a%% *}" ] || echo "exit on space" # if $a has an space.
$ nl='
' # define a new line in the usual posix way.
$ [ "$a" = "${a%%"$nl"*}" ] || echo "exit on newline" # if $a has a newline.
Jika solusi yang digunakan kuat di salah satu item tersebut, hapus tes.
Dalam bash, sub-direktori dapat diuji sekaligus dengan ** yang dijelaskan di atas.
Ada beberapa cara untuk memasukkan file dot, solusi Posix adalah:
set -- "$dir"/* "$dir"/.[!.]* "$dir"/..?*
Temukan
Jika find harus digunakan karena alasan tertentu, ganti pembatas dengan NUL (0x00).
bash 4.4+
$ readarray -t -d '' arr < <(find "$dir" -type f -name file\* -print0)
$ printf '<%s>\n' "${arr[@]}"
<deep/inside/a/dir/file name>
<deep/inside/a/dir/file with a
newline>
<deep/inside/a/dir/directory/file name>
<deep/inside/a/dir/directory/file with a
newline>
<deep/inside/a/dir/directory/file>
<deep/inside/a/dir/file>
bash 2.05+
i=1 # lets start on 1 so it works also in zsh.
while IFS='' read -d '' val; do
arr[i++]="$val";
done < <(find "$dir" -type f -name \*file -print0)
printf '<%s>\n' "${arr[@]}"
POSIXLY
Untuk membuat solusi POSIX yang valid di mana find tidak memiliki pembatas NUL dan tidak ada -d
(atau -a
) untuk membaca kita perlu pendekatan yang berbeda secara keseluruhan.
Kita perlu menggunakan kompleks -exec
dari find dengan panggilan ke shell:
find "$dir" -type f -exec sh -c '
for f do
echo "<$f>"
done
' sh {} +
Atau, jika yang diperlukan adalah pilih (pilih adalah bagian dari bash, bukan sh):
$ find "$dir" -type f -exec bash -c '
select f; do echo "<$f>"; break; done ' bash {} +
1) deep/inside/a/dir/file name
2) deep/inside/a/dir/zz last file
3) deep/inside/a/dir/file with a
newline
4) deep/inside/a/dir/directory/file name
5) deep/inside/a/dir/directory/zz last file
6) deep/inside/a/dir/directory/file with a
newline
7) deep/inside/a/dir/directory/file
8) deep/inside/a/dir/file
#? 3
<deep/inside/a/dir/file with a
newline>
[1] Pohon ini (\ 012 adalah baris baru):
$ tree
.
└── deep
└── inside
└── a
└── dir
├── directory
│ ├── file
│ ├── file name
│ └── file with a \012newline
├── file
├── file name
├── otherfile
├── with a\012newline
└── zz last file
Dapat dibangun dengan dua perintah ini:
$ mkdir -p deep/inside/a/dir/directory/
$ touch deep/inside/a/dir/{,directory/}{file{,\ {name,with\ a$'\n'newline}},zz\ last\ file}