সাব-ডিরেক্টরিগুলির পরিবর্তে প্যারেন্ট ডিরেক্টরিগুলিতে সন্ধান করুন


45

আমি একটি ফাইল গাছের গভীরে বাসা বেঁধেছি এবং আমি খুঁজে পেতে চাই যে কোন পিতৃ ডিরেক্টরিতে কোনও ফাইল রয়েছে।

উদাহরণস্বরূপ, আমি নেস্টেড গিট রিপোজিটরিগুলির একটি সেটে আছি এবং আমি বর্তমানে যে ফাইলগুলিতে আছি সেগুলি নিয়ন্ত্রণ করে .git ডিরেক্টরিটি সন্ধান করতে চাই। আমি সন্ধান-অনুসন্ধান নাম ".git" এর মতো কিছু আশা করব

উত্তর:


16

আরও সাধারণ সংস্করণ যা findবিকল্পগুলি ব্যবহার করে :

#!/bin/bash
set -e
path="$1"
shift 1
while [[ $path != / ]];
do
    find "$path" -maxdepth 1 -mindepth 1 "$@"
    # Note: if you want to ignore symlinks, use "$(realpath -s "$path"/..)"
    path="$(readlink -f "$path"/..)"
done

উদাহরণস্বরূপ (ধরে নিলাম স্ক্রিপ্টটি সংরক্ষণ করা হয়েছে find_up.sh)

find_up.sh some_dir -iname "foo*bar" -execdir pwd \;

... প্যাটার্ন সহ একটি ফাইল পাওয়া যায় এমন পর্যন্ত সমস্ত some_dirপূর্বপুরুষের নাম (নিজেকে সহ) মুদ্রণ করবে will/

readlink -fউপরের স্ক্রিপ্টটি ব্যবহার করার সময় মন্তব্যে যেমন উল্লেখ করা হয়েছে তেমন পথে প্রতীকগুলি অনুসরণ করবে। realpath -sপরিবর্তে আপনি ব্যবহার করতে পারেন , যদি আপনি নামের সাথে পাথগুলি অনুসরণ করতে চান ("/ foo / বার" "foo" তে উঠে যাবে এমনকি "বার" একটি সিমলিংক হলেও) - এটির জন্য realpathডিফল্টরূপে ইনস্টল করা হয়নি যা ইনস্টল করতে হবে বেশিরভাগ প্ল্যাটফর্ম


এর সাথে সমস্যাটি হ'ল লিঙ্কগুলি সমাধান করে। উদাহরণস্বরূপ যদি আমি ~ / foo / বারে আছি, এবং বারটি / কিছু / অন্য / জায়গায় সিমিলিংক হয়, তবে then / foo এবং ~ / কখনই অনুসন্ধান করা হবে না।
এরিক অ্যারোনস্টি

@ এরিক অ্যারোনস্টি, আপনি ঠিক বলেছেন - উত্তরটি আপডেট করেছেন। আপনি realpath -sচান আচরণ পেতে আপনি ব্যবহার করতে পারেন।
sinelaw

যখন আপনি অনুসন্ধানের জন্য একটি পুরো পথ নির্দিষ্ট করে তা কাজ করে। দুঃখের বিষয়, 5..৮ শতাংশে, রিয়েলপথ-এস <ডিআর> এর একটি বাগ রয়েছে যেখানে <dir> আপেক্ষিক থাকলে এটি যেকোন উপায়ে সিমলিংকগুলি সমাধান করে ... যদিও এটি ডকুমেন্টেশন থাকা সত্ত্বেও।
এরিক অ্যারোনস্টি

readlinkমান অংশ নয়। একটি পোর্টেবল স্ক্রিপ্ট কেবলমাত্র পসিক্স শেল বৈশিষ্ট্য সহ প্রয়োগ করা যেতে পারে।
দক্ষতার সাথে

1
এফওয়াইআই, এটি zsh এ কাজ করে না কারণ এটি $ পাথের পুনরায় সংজ্ঞা দেয় যাতে শেলটি খুঁজে পায় না findবা readlink। আমি $curpathপরিবর্তে এর মতো কিছুতে এটি পরিবর্তন করার পরামর্শ দিচ্ছি যাতে এটি শেল পরিবর্তনশীলের ছায়া না দেয়।
স্কাইলার

28
git rev-parse --show-toplevel

আপনি যদি একের মধ্যে থাকেন তবে বর্তমান সংগ্রহস্থলের শীর্ষ স্তরের ডিরেক্টরিটি মুদ্রণ করবে।

অন্যান্য সম্পর্কিত বিকল্প:

# `pwd` is inside a git-controlled repository
git rev-parse --is-inside-work-tree
# `pwd` is inside the .git directory
git rev-parse --is-inside-git-dir

# path to the .git directory (may be relative or absolute)
git rev-parse --git-dir

# inverses of each other:
# `pwd` relative to root of repository
git rev-parse --show-prefix
# root of repository relative to `pwd`
git rev-parse --show-cdup

4
এটি কেবল গিটের জন্যই কাজ করে। প্রশ্নটি আরও জেনেরিক।
অ্যালেক্স

1
এটি একটি খালি
রেপোতে

19

গিলসের উত্তরের একটি সাধারণ সংস্করণ, ম্যাচটি সন্ধান করতে ব্যবহৃত প্রথম প্যারামিটার:

find-up () {
  path=$(pwd)
  while [[ "$path" != "" && ! -e "$path/$1" ]]; do
    path=${path%/*}
  done
  echo "$path"
}

সিম-লিঙ্কগুলির ব্যবহার রাখে।


15

এটি করতে পারে না সন্ধান করুন। আমি শেল লুপের চেয়ে সহজ কিছু ভাবতে পারি না। (স্বাক্ষরিত, ধরে নেই /.git)

git_root=$(pwd -P 2>/dev/null || command pwd)
while [ ! -e "$git_root/.git" ]; do
  git_root=${git_root%/*}
  if [ "$git_root" = "" ]; then break; fi
done

গিট সংগ্রহস্থলের নির্দিষ্ট ক্ষেত্রে, আপনি গিটকে আপনার কাজটি করতে দিতে পারেন।

git_root=$(GIT_EDITOR=echo git config -e)
git_root=${git_root%/*}

1
শীতল, এটি আমাকে একটি সাধারণ সমাধানের পথে নিয়ে যায় - যা আমি এখানে অন্য উত্তর হিসাবে পোস্ট করি।
ভিনসেন্ট শাইব

12

আপনি যদি প্রসারিত গ্লোব্বিং সক্ষম করে zsh ব্যবহার করে থাকেন তবে আপনি অননিলার দিয়ে এটি করতে পারেন:

(../)#.git(:h)   # relative path to containing directory, eg. '../../..', '.'
(../)#.git(:a)   # absolute path to actual file, eg. '/home/you/src/prj1/.git'
(../)#.git(:a:h) # absolute path to containing directory, eg. '/home/you/src/prj1'

ব্যাখ্যা (থেকে উদ্ধৃত man zshexpn):

পুনরাবৃত্ত গ্লোব্বিং

ফর্মের একটি প্যাথনাম উপাদানটি (foo/)#প্যাটার্ন ফু-র সাথে মেলে শূন্য বা আরও বেশি ডিরেক্টরি সহ একটি পথের সাথে মেলে। সংক্ষিপ্ত হিসাবে, **/সমান (*/)#

সংশোধনকারীদের

Wordচ্ছিক শব্দ নকশাকারীর পরে, আপনি নীচের এক বা একাধিক সংশোধকগুলির ক্রম যুক্ত করতে পারেন, প্রতিটি ':' এর আগে রয়েছে। এই পরিবর্তনকারীগুলি ফাইলের নাম উত্পাদন এবং পরামিতি প্রসারণের ফলাফলগুলিতে কাজ করে, যেখানে উল্লিখিত হয় না।

  • একটি
    • কোনও ফাইলের নামকে পরম পথে পরিণত করুন: বর্তমান ডিরেক্টরিটি প্রয়োজনে, পূর্বে সংশোধন করে এবং '..' এবং 'এর যে কোনও ব্যবহারের সমাধান করে।'
  • একজন
    • 'হিসেবে একটি ', কিন্তু সমাধান সিম্বলিক লিংক ব্যবহার যেখানে সম্ভব। লক্ষ করুন যে '..' এর রেজোলিউশনটি প্রতীকী লিঙ্কগুলির সমাধানের আগে ঘটে। আপনার সিস্টেমে realpathসিস্টেম কল (আধুনিক সিস্টেমগুলি না করে) এই কলটি সমান ।
    • মাথা রেখে একটি অনুসরণীয় পথের নাম উপাদান সরান। এটি ' dirname' এর মতো কাজ করে ।

ক্রেডিট: Fauxউপর #zshব্যবহারের প্রাথমিক পরামর্শের জন্য (../)#.git(:h)


এটি আশ্চর্যজনক ... যদি আমি কেবল বুঝতে পারি (ইঙ্গিত: আপনার আমাকে বলা উচিত ) কী (../)করছে ... ওহ, এবং কে / কী Faux on #zsh?
অ্যালেক্স ধূসর

1
@alexgray (../)একা বেশি বোঝায় না, তবে এর (../)#অর্থ হল 0 বা ততোধিক বারের প্রথম বন্ধনীর অভ্যন্তরে প্যাটার্নটি প্রসারিত করার চেষ্টা করুন এবং কেবলমাত্র ফাইল সিস্টেমে বিদ্যমান সেইগুলি ব্যবহার করুন। যেহেতু আমরা 0 টি থেকে পিতামাতার ডিরেক্টরিগুলিতে প্রসারিত করছি, আমরা কার্যকরভাবে ফাইল সিস্টেমের মূল পর্যন্ত উপরের দিকে অনুসন্ধান করব (দ্রষ্টব্য: আপনি সম্ভবত প্যাটার্নটিকে অর্থবহ করে তুলতে কিছু যুক্ত করতে চান তবে আলোকায়ন কার্যকর করার জন্য print -l (../)#)। এবং #zshএটি একটি আইআরসি চ্যানেল, Fauxএটির একটি ব্যবহারকারীর নাম। Fauxসমাধান প্রস্তাব, তাই কৃতিত্ব।
কল্পনা

1
এটি তাদের সকলকে প্রসারিত করবে। আপনি চাইতে পারেন: (../)#.git(/Y1:a:h)প্রথম পাওয়া একটিতে থামার জন্য (zsh এর সাম্প্রতিক সংস্করণ সহ)
স্টাফেন চেজেলাস

1
অনেক সহায়ক, ধন্যবাদ। বর্ধিত globbing Do সক্রিয় করার জন্যsetopt extended_glob
Shlomi

0

ফাইন্ডআপের এই সংস্করণটি @ সাইনলাওর জবাবের মতো "সন্ধান করুন" সিনট্যাক্সকে সমর্থন করে, তবে রিয়েলপথের প্রয়োজন ছাড়াই প্রতীকগুলি সমর্থন করে। এটি একটি alচ্ছিক "স্টপ এট" বৈশিষ্ট্যটিকেও সমর্থন করে, তাই এটি কাজ করে: findup .:~ -name foo... বাড়ির দিরকে না পেরে ফু অনুসন্ধান করে।

#!/bin/bash

set -e

# get optional root dir
IFS=":" && arg=($1)
shift 1
path=${arg[0]}
root=${arg[1]}
[[ $root ]] || root=/
# resolve home dir
eval root=$root

# use "cd" to prevent symlinks from resolving
cd $path
while [[ "$cur" != "$root" && "$cur" != "/" ]];
do
    cur="$(pwd)"
    find  "$cur/"  -maxdepth 1 -mindepth 1 "$@"
    cd ..
done

0

আমি দেখতে পেয়েছি যে সিমলিংকের সাথে কাজ করা অন্য কয়েকটি বিকল্পকে হত্যা করে। বিশেষত গিট নির্দিষ্ট উত্তর। আমি অর্ধেক আমার নিজের প্রিয় আউট তৈরি করেছি এই মূল উত্তর যে বেশ effecient আছে।

#!/usr/bin/env bash

# usage: upsearch .git

function upsearch () {
    origdir=${2-`pwd`}
    test / == "$PWD" && cd "$origdir" && return || \
    test -e "$1" && echo "$PWD" && cd "$origdir" && return || \
    cd .. && upsearch "$1" "$origdir"
}

আমি আমার গো প্রকল্পগুলির জন্য সিমলিংকগুলি ব্যবহার করছি কারণ গো নির্দিষ্ট স্থানে সোর্স কোড চায় এবং আমি আমার প্রকল্পগুলি ~ / প্রকল্পের আওতায় রাখতে চাই। আমি $ GOPATH / src এ প্রকল্পটি তৈরি করে them / প্রকল্পগুলিতে সেগুলিকে সংযুক্ত করি। সুতরাং running git rev-parse --show-toplevel/ প্রকল্প ডিরেক্টরি নয়, $ GOPATH ডিরেক্টরিটি প্রিন্ট করছে। এই সমাধানটি সেই সমস্যার সমাধান করে।

আমি বুঝতে পারি এটি একটি খুব নির্দিষ্ট পরিস্থিতি, তবে আমি মনে করি সমাধানটি মূল্যবান।


0

রুট ডিরেক্টরিতে থাকা ফাইলগুলির জন্য ভিনসেন্ট শাইবের সমাধান কাজ করে না।

নিম্নলিখিত সংস্করণটি করে, এবং আপনাকে প্রথম দিকটিকে আর্গুমেন্ট হিসাবে পাস করতে দেয়।

find-up() {
    path="$(realpath -s "$1")"

    while ! [ -e "$path"/"$2" ] && [ -n "$path" ]; do
        path="${path%/*}"
    done

    [ -e "$path"/"$2" ] && echo "$path"/"$2"
}

0

আমি সাইনালোর সমাধানটি পসিক্স হিসাবে সংশোধন করেছি । এটি প্রতিলিঙ্কগুলি অনুসরণ করে না এবং ডু উইল লুপ ব্যবহার করে মূল ডিরেক্টরিটি অনুসন্ধান করে includes

find-up:
#!/usr/bin/env sh

set -e # exit on error
# Use cd and pwd to not follow symlinks.
# Unlike find, default to current directory if no arguments given.
directory="$(cd "${1:-.}"; pwd)"

shift 1 # shift off the first argument, so only options remain

while :; do
  # POSIX, but gets "Permission denied" on private directories.
  # Use || true to allow errors without exiting on error.
  find "$directory" -path "${directory%/}/*/*" -prune -o ! -path "$directory" "$@" -print || true

  # Equivalent, but -mindepth and -maxdepth aren't POSIX.
  # find "$directory" -mindepth 1 -maxdepth 1 "$@"

  if [ "$directory" = '/' ]; then
    break # End do while loop
  else
    directory=$(dirname "$directory")
  fi
done
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.