2010-01-22 10 views
6

मैं एक bash स्क्रिप्ट (उपनिर्देशिकाएं) एक निर्देशिका की सामग्री के माध्यम से पुनरावृति जाएगा लिख ​​सकते हैं और निम्नलिखित प्रतिस्थापन प्रदर्शन करने की जरूरत है:बैश पटकथा चुनौती

  • 'बार' के साथ किसी भी फ़ाइल नामों में 'foo' की जगह ले
  • अब तक सब मुझे मिल गया है 'बार'

के साथ किसी भी फ़ाइलों की सामग्री में 'foo' की जगह ले

find . -name '*' -exec {} \; 
है

:-)

+6

क्योंकि मेरे माता-पिता के रूप में मुझे पर्याप्त स्नेह नहीं दिखा था एक बच्चा –

+0

अहहा मैं आपको उस टिप्पणी के लिए +1 दूंगा। अब, यह होमवर्क है? –

+0

नहीं, यह होमवर्क नहीं है। यदि आप मेरी प्रोफ़ाइल देखते हैं तो यह (उम्मीद है) स्पष्ट है कि मैं छात्र नहीं हूं। –

उत्तर

2

आरएच rename के साथ:

find -f \(-exec sed -i s/foo/bar/g \; , -name \*foo\* -exec rename foo bar {} \; \) 
2
find "[email protected]" -depth -exec sed -i -e s/foo/bar/g {} \; , -name '*foo*' -print0 | 
while read -d '' file; do 
    base=$(basename "$file") 
    mv "$file" "$(dirname "$file")/${base//foo/bar}" 
done 
+0

अफसोस की बात है, 'ऑपरेटर मानक नहीं है, और ऐसा लगता है कि केवल जीएनयू' ढूंढ 'में मौजूद है। साथ ही, यह निर्देशिकाओं के साथ-साथ फ़ाइलों को 'sed' में पास करता है, आपको त्रुटियों से बचने के लिए' टाइप प्रकार 'जोड़ना होगा। मुझे यह पसंद है क्योंकि यह यहां के अधिकांश अन्य उत्तरों की तुलना में अधिक संक्षिप्त है। –

+0

खैर, 'sed' किसी निर्देशिका पर त्रुटि होगी लेकिन 'find' जारी रहेगा ;-) बिना', 'मुझे लगता है कि इसे या तो दो' खोज 'आमंत्रण में विभाजित किया जाना चाहिए या बैश भाग को और अधिक काम करना होगा। – ephemient

1

अपडेट: 1632 ईएसटी

  • अब खाली स्थान के लेकिन संभालती है ', जबकि आइटम पढ़ा' कभी नहीं समाप्त हो जाता है। बेहतर, लेकिन अभी भी सही नहीं है। इस पर काम कर रहे रखेंगे।

ए जे @ mmdev0: ~/foo_to_bar $ बिल्ली script.sh

#!/bin/bash 

dirty=true 
while ${dirty} 
do 
    find ./ -name "*" |sed -s 's/ /\ /g'|while read item 
    do 
     if [[ ${item} == "./script.sh" ]] 
     then 
      continue 
     fi 
     echo "working on: ${item}" 

     if [[ ${item} == *foo* ]] 
     then 
      rename 's/foo/bar/' "${item}" 
      dirty=true 
      break 
     fi 

     if [[ ! -d ${item} ]] 
     then 
      cat "${item}" |sed -e 's/foo/bar/g' > "${item}".sed; mv "${item}".sed "${item}" 
     fi 
     dirty=false 
    done 
done 
+0

'\" ... \ "में आइटम के लिए गलत काम करता है अगर किसी फ़ाइल नाम में व्हाइटस्पेस होता है। – ephemient

+0

@ephemient सही आप इस फिक्स पर काम कर रहे हैं ... –

1
#!/bin/bash 
function RecurseDirs 
{ 
oldIFS=$IFS 
IFS=$'\n' 
for f in * 
do 
    if [[ -f "${f}" ]]; then 
    newf=`echo "${f}" | sed -e 's/foo/bar/g'` 
    sed -e 's/foo/bar/g' < "${f}" > "${newf}" 
    fi 
    if [[ -d "${f}" && "${f}" != '.' && "${f}" != '..' && ! -L "${f}" ]]; then 
    cd "${f}" 
    RecurseDirs . 
    cd .. 
    fi 
done 
IFS=$oldIFS 
} 
RecurseDirs . 
+0

बहुत अच्छी, भयानक भाषा :) –

+0

@ डॉन: एक कॉपी और पेस्ट त्रुटि की तरह लगता है। इसके बजाय इसे टाइप करने का प्रयास करें। @ डेरेनॉल्ड: सिम्लिंक के लिए देखें, आप निर्देशिका लूप में फंस सकते हैं या कहीं और कहीं भी जा सकते हैं '..' शायद ऐसा नहीं हो सकता है जो आपको लगता है। (हां, बैश आमतौर पर इसे ठीक करने का प्रयास करता है, लेकिन यह एक उदारवादी है। Http://stackoverflow.com/questions/2105572 देखें) – ephemient

+0

@ephemient: हाँ, आप सही हैं - यह आस-पास की सबसे सुरक्षित चीज़ नहीं है। ठीक है, मुझे लगता है। – dreynold

0

बैश 4,0

#!/bin/bash 
shopt -s globstar 
path="/path" 
cd $path 
for file in ** 
do 
    if [ -d "$file" ] && [[ "$file" =~ ".*foo.*" ]];then 
     echo mv "$file" "${file//foo/bar}" 
    elif [ -f "$file" ];then 
     while read -r line 
     do 
      case "$line" in 
       *foo*) line="${line//foo/bar}";; 
      esac 
      echo "$line" 
     done < "$file" > temp 
     echo mv temp "$file" 

    fi 
done 

को दूर 'गूंज' परिवर्तन के लिए प्रतिबद्ध करने

+0

मामूली नाइट: यदि '$ line'' -e'' या '' '' नहीं है या कुछ अन्य स्विच जो बैश 'echo' पहचानता है, तो यह फ़ाइल में उलझ जाएगा। बिना शर्त रूप से प्रतिस्थापन करने में कोई हानि नहीं है, इसलिए मैं उस पूरे शरीर को 'printf'% s \ n '"$ {line // foo/bar}" में कटौती करता हूं। एक अन्य नाइट: आप पहले से ही बैश के डबल-ब्रैकेट टेस्ट का उपयोग कर रहे हैं, क्यों छोटे '[[$ file = * foo *]]' लिखें? उच्च स्तरीय डायरनाम में परिवर्तन होने पर आपको कठोर-से-ठीक समस्याएं होती हैं और आप निर्देशिका पेड़ के नीचे कुछ और काम कर रहे हैं, और गैर-निर्देशिकाओं का कोई नाम नहीं है (जो होना चाहिए, ओपी के प्रश्न के मेरे पढ़ने से)। – ephemient

0

for f in `tree -fi | grep foo`; do sed -i -e 's/foo/bar/g' $f ; done

0

फिर भी एक और खोज-कार्यकारी समाधान: लगता है-कार्यकारी करने के लिए

find . -type f -exec bash -c ' 
path="{}"; 
dirName="${path%/*}"; 
baseName="${path##*/}"; 
nbaseName="${baseName/foo/bar}"; 
#nbaseName="${baseName//foo/bar}"; 
# cf. http://www.bash-hackers.org/wiki/doku.php?id=howto:edit-ed 
ed -s "${path}" <<< $'H\ng/foo/s/foo/bar/g\nwq'; 
#sed -i "" -e 's/foo/bar/g' "${path}"; # alternative for large files 
exec mv -iv "{}" "${dirName}/${nbaseName}" 
' \; 
+0

यदि फ़ाइल नाम में "या \ है, तो आपको '-exec bash -c' पथ = $ 1; ... '- {} \;' जैसे कुछ और उपयोग करना चाहिए। – ephemient

0

सुधार gregb द्वारा दृष्टिकोण (जोड़ने उद्धरण):

# compare 

bash -c ' 
    echo $'a\nb\nc' 
' 

bash -c ' 
    echo $'"'a\nb\nc'"' 
' 

# therefore we need 

find . -type f -exec bash -c ' 
... 
ed -s "${path}" <<< $'"'H\ng/foo/s/foo/bar/g\nwq'"'; 
... 
' \; 
संबंधित मुद्दे