Saya ingin menemukan semua subfolder, yang berisi file penurunan harga dengan nama yang sama (dan ekstensi .md
).
Misalnya: Saya ingin Menemukan subfolder berikut:
Apple/Banana/Orange #Apple/Banana/Orange/Orange.md exists
Apple/Banana #Apple/Banana/Banana.md exists
Apple/Banana/Papaya #Apple/Banana/Papaya/Papaya.md exists
- Catatan: Mungkin ada file atau subdirektori lain dalam direktori.
Ada saran?
Solusi untuk masalah ini dapat diuji menggunakan kode berikut:
#!/usr/bin/env bash
# - goal: "Test"
# - author: Nikhil Agarwal
# - date: Wednesday, August 07, 2019
# - status: P T' (P: Prototyping, T: Tested)
# - usage: ./Test.sh
# - include:
# 1.
# - refer:
# 1. [directory - Find only those folders that contain a File with the same name as the Folder - Unix & Linux Stack Exchange](/unix/534190/find-only-those-folders-that-contain-a-file-with-the-same-name-as-the-folder)
# - formatting:
# shellcheck disable=
#clear
main() {
TestData
ExpectedOutput
TestFunction "${1:?"Please enter a test number, as the first argument, to be executed!"}"
}
TestFunction() {
echo "Test Function"
echo "============="
"Test${1}"
echo ""
}
Test1() {
echo "Description: Thor"
find . -type f -regextype egrep -regex '.*/([^/]+)/\1\.md$' | sort
echo "Observation: ${Green:=}Pass, but shows filepath instead of directory path${Normal:=}"
}
Test2() {
echo "Description: Kusalananda1"
find . -type d -exec sh -c '
dirpath=$1
set -- "$dirpath"/*.md
[ -f "$dirpath/${dirpath##*/}.md" ] && [ "$#" -eq 1 ]' sh {} \; -print | sort
echo "Observation: ${Red:=}Fails as it ignores B.md${Normal:=}"
}
Test3() {
echo "Description: Kusalananda2"
find . -type d -exec sh -c '
for dirpath do
set -- "$dirpath"/*.md
if [ -f "$dirpath/${dirpath##*/}.md" ] && [ "$#" -eq 1 ]
then
printf "%s\n" "$dirpath"
fi
done' sh {} + | sort
echo "Observation: ${Red:=}Fails as it ignores B.md${Normal:=}"
}
Test4() {
echo "Description: steeldriver1"
find . -type d -exec sh -c '[ -f "$1/${1##*/}.md" ]' find-sh {} \; -print | sort
echo "Observation: ${Green:=}Pass${Normal:=}"
}
Test5() {
echo "Description: steeldriver2"
find . -type d -exec sh -c '
for d do
[ -f "$d/${d##*/}.md" ] && printf "%s\n" "$d"
done' find-sh {} + | sort
echo "Observation: ${Green:=}Pass${Normal:=}"
}
Test6() {
echo "Description: Stéphane Chazelas"
find . -name '*.md' -print0 \
| gawk -v RS='\0' -F/ -v OFS=/ '
{filename = $NF; NF--
if ($(NF)".md" == filename) include[$0]
else exclude[$0]
}
END {for (i in include) if (!(i in exclude)) print i}'
echo "Observation: ${Red:=}Fails as it ignores B.md${Normal:=}"
}
Test7() {
echo "Description: Zach"
#shellcheck disable=2044
for fd in $(find . -type d); do
dir=${fd##*/}
if [ -f "${fd}/${dir}.md" ]; then
ls "${fd}/${dir}.md"
fi
done
echo "Observation: ${Green:=}Pass but shows filepath instead of directory${Normal:=}"
}
ExpectedOutput() {
echo "Expected Output"
echo "==============="
cat << EOT
./GeneratedTest/A
./GeneratedTest/A/AA
./GeneratedTest/B
./GeneratedTest/C/CC1
./GeneratedTest/C/CC2
EOT
}
TestData() {
rm -rf GeneratedTest
mkdir -p GeneratedTest/A/AA
touch GeneratedTest/index.md
touch GeneratedTest/A/A.md
touch GeneratedTest/A/AA/AA.md
mkdir -p GeneratedTest/B
touch GeneratedTest/B/B.md
touch GeneratedTest/B/index.md
mkdir -p GeneratedTest/C/CC1
touch GeneratedTest/C/index.md
touch GeneratedTest/C/CC1/CC1.md
mkdir -p GeneratedTest/C/CC2
touch GeneratedTest/C/CC2/CC2.md
mkdir -p GeneratedTest/C/CC3
touch GeneratedTest/C/CC3/CC.md
mkdir -p GeneratedTest/C/CC4
}
main "$@"
foo/foo.md
danfoo/bar.md
harusfoo
dimasukkan atau dikecualikan?-printf
dengan find, Anda bisa mendapatkan bagian apa pun dari pertandingan yang Anda inginkan, lihat hasil edit sayaJawaban:
Dengan asumsi file Anda masuk akal, yaitu tidak perlu untuk
-print0
dll. Anda dapat melakukan ini dengan GNU temukan seperti ini:Keluaran:
Jika Anda hanya ingin nama direktori, tambahkan
-printf
argumen:Output saat dijalankan pada data uji Anda yang diperbarui:
sumber
find . -type f | egrep '.*/([^/]+)/\1\.md$'
print0
.%h
di printf digunakan untuk tipe data int untuk diformat. Referensi: string format printf - Wikipedia . Bisakah Anda jelaskan bagian itu? Bagaimana%h
cara digunakan di sini?find
, lihat bagian 3.2.2.1 di manual untuk detail lebih lanjut.Pada sistem GNU, Anda dapat melakukan sesuatu seperti:
sumber
zsh
solusi sebelumnya (saya yakin, ada dua upvotes), dan jangan ragu untuk menunjukkan kekurangan di dalamnya yang mungkin mendorong Anda untuk menghapusnya.Di atas akan menemukan semua direktori di bawah direktori saat ini (termasuk direktori saat ini) dan akan menjalankan skrip shell pendek untuk masing-masing.
Kode shell akan menguji apakah ada file penurunan harga dengan nama yang sama dengan direktori di dalam direktori, dan apakah ini satu-satunya
*.md
nama dalam direktori itu. Jika file seperti itu ada dan jika itu satu-satunya*.md
nama, skrip inline shell keluar dengan status keluar nol. Kalau tidak, ia keluar dengan status keluar non-nol (kegagalan pensinyalan).The
set -- "$dirpath"/*.md
bit akan mengatur parameter posisi ke daftar nama path cocok dengan pola (sesuai dengan nama apapun dengan akhiran.md
dalam direktori). Kami kemudian dapat menggunakan$#
nanti untuk melihat berapa banyak pertandingan yang kami dapatkan dari ini.Jika skrip shell berhasil keluar,
-print
akan mencetak jalur ke direktori yang ditemukan.Versi yang sedikit lebih cepat yang menggunakan lebih sedikit pemanggilan skrip inline, tetapi itu tidak membuat Anda berbuat lebih banyak dengan nama path yang ditemukan
find
itu sendiri (skrip inline mungkin akan diperluas lebih lanjut):Perintah yang sama tetapi tanpa peduli apakah ada
.md
file lain di direktori:Lihat juga:
sumber
Antara
atau
Untuk menghindari menjalankan satu
sh
per file.Ini
find-sh
adalah string arbitrer yang menjadi parameter posisi zeroth pada shell$0
- membuatnya sesuatu yang mudah diingat dapat membantu debugging jika shell menemukan kesalahan (orang lain mungkin menyarankan menggunakan plainsh
atau bahkan_
sebagai parameter "skip" default).sumber
Ini milik saya. Saya menambahkan beberapa direktori dan file untuk memverifikasi. Saya juga bosan, jadi saya menambahkan waktu modifikasi dan MD5 terakhir. Mungkin Anda sedang mencari duplikat.
sumber
Ini akan membutuhkan sedikit logika.
Anda juga dapat mengadaptasinya agar sesuai dengan satu liner dengan menggunakan blok kode.
EDIT: Bash sulit.
basedir
bukan perintah,dirname
tidak melakukan apa yang saya pikir itu lakukan, jadi mari kita lanjutkan dengan ekspansi parameter.sumber
dirname
adalah perintah yang Anda cari, dan tugas tidak dapat memiliki ruang di sekitar=
.