मैं निम्नलिखित प्रारूप में एक निर्देशिका को कैसे समतल कर सकता हूं?
इससे पहले: ./aaa/bbb/ccc.png
उपरांत: ./aaa-bbb-ccc.png
./foo/bar/baz.png
और ./foo-bar-baz.png
दोनों मौजूद हैं। मुझे लगता है कि आप बाद वाले को पूर्व से बदलना नहीं चाहते हैं?
मैं निम्नलिखित प्रारूप में एक निर्देशिका को कैसे समतल कर सकता हूं?
इससे पहले: ./aaa/bbb/ccc.png
उपरांत: ./aaa-bbb-ccc.png
./foo/bar/baz.png
और ./foo-bar-baz.png
दोनों मौजूद हैं। मुझे लगता है कि आप बाद वाले को पूर्व से बदलना नहीं चाहते हैं?
जवाबों:
चेतावनी: मैंने इनमें से अधिकांश कमांड सीधे अपने ब्राउज़र में टाइप किए। कैवेट लेक्टर।
Zsh और zmv के साथ :
zmv -o -i -Qn '(**/)(*)(D)' '${1//\//-}$2'
स्पष्टीकरण: पैटर्न **/*
वर्तमान निर्देशिका की उपनिर्देशिकाओं में सभी फ़ाइलों से मेल खाता है, पुनरावर्ती रूप से (यह वर्तमान निर्देशिका में फ़ाइलों से मेल नहीं खाता है, लेकिन इनका नाम बदलने की आवश्यकता नहीं है)। कोष्ठक के पहले दो जोड़े ऐसे समूह हैं जिन्हें प्रतिस्थापन पाठ के रूप में $1
और संदर्भित किया जा सकता है $2
। कोष्ठक की अंतिम जोड़ी D
ग्लोब क्वालीफायर को जोड़ती है ताकि डॉट फाइलें लोप न हों। विकल्प -o -i
को पास करने का मतलब है ताकि आपको संकेत -i
दिया mv
जाए कि क्या कोई मौजूदा फ़ाइल अधिलेखित की जाएगी।
केवल POSIX टूल के साथ:
find . -depth -exec sh -c '
for source; do
case $source in ./*/*)
target="$(printf %sz "${source#./}" | tr / -)";
mv -i -- "$source" "${target%z}";;
esac
done
' _ {} +
स्पष्टीकरण: case
कथन वर्तमान निर्देशिका और वर्तमान निर्देशिका के शीर्ष-स्तरीय उपनिर्देशिकाओं को छोड़ देता है। target
स्रोत फ़ाइल नाम शामिल है ( $0
) प्रमुख ./
छीन लिया और डैश के साथ सभी स्लैशों के साथ, एक अंतिम z
। z
यदि फ़ाइल नाम एक नई सीमा के साथ समाप्त होता है, तो अंतिम होता है: अन्यथा कमांड प्रतिस्थापन इसे बंद कर देगा।
यदि आपका find
समर्थन नहीं करता है -exec … +
(OpenBSD, मैं आपको देख रहा हूं):
find . -depth -exec sh -c '
case $0 in ./*/*)
target="$(printf %sz "${0#./}" | tr / -)";
mv -i -- "$0" "${target%z}";;
esac
' {} \;
बैश (या ksh93) के साथ, आपको डैश द्वारा स्लैश को बदलने के लिए किसी बाहरी कमांड को कॉल करने की आवश्यकता नहीं है, आप स्ट्रिंग प्रतिस्थापन निर्माण के साथ ksh93 पैरामीटर विस्तार का उपयोग कर सकते हैं ${VAR//STRING/REPLACEMENT}
:
find . -depth -exec bash -c '
for source; do
case $source in ./*/*)
source=${source#./}
target="${source//\//-}";
mv -i -- "$source" "$target";;
esac
done
' _ {} +
for source
उदाहरण पहले प्रस्तुत फ़ाइल / dir याद आती है ... मैं अंत में पता चला गया है तुम क्यों (सामान्य रूप से) का इस्तेमाल किया है _
के रूप में $0
महान जवाब के लिए धन्यवाद :) ... और। मैं उनसे बहुत कुछ सीखता हूं।
जबकि यहाँ पहले से ही अच्छे उत्तर हैं, मुझे यह अधिक सहज लगता है, भीतर bash
:
find aaa -type f -exec sh -c 'new=$(echo "{}" | tr "/" "-" | tr " " "_"); mv "{}" "$new"' \;
aaa
आपकी मौजूदा निर्देशिका कहां है इसमें मौजूद फ़ाइलों को वर्तमान निर्देशिका में ले जाया जाएगा (केवल आहा में खाली निर्देशिकाओं को छोड़कर)। दोनों कॉल tr
दोनों निर्देशिकाओं और रिक्त स्थान को संभालने के लिए (बच गए स्लैश के लिए तर्क के बिना - पाठक के लिए एक व्यायाम)।
मैं इसे अधिक सहज और अपेक्षाकृत आसान मानता हूं। यानी मैं find
मापदंडों को बदल सकता हूं अगर मैं केवल .png फ़ाइलों को ढूंढना चाहता हूं। मैं tr
कॉल बदल सकता हूं , या आवश्यकतानुसार जोड़ सकता हूं । और मैं echo
इससे पहले जोड़ सकता हूं mv
अगर मैं नेत्रहीन जांच करना चाहता हूं कि यह सही काम करेगा (तब अतिरिक्त के बिना दोहराएं echo
यदि चीजें सही दिखती हैं:
find aaa -name \*.png -exec sh -c 'new=$(echo "{}" | tr "/" "-" | tr " " "_"); echo mv "{}" "$new"' \;
ध्यान दें कि मैं उपयोग कर रहा हूं find aaa
... और find .
... या find aaa/
... जैसा कि बाद के दो अंतिम फ़ाइल नाम में अजीब कलाकृतियों को छोड़ देगा।
find . -mindepth 2 -type f -name '*' |
perl -l000ne 'print $_; s/\//-/g; s/^\.-/.\// and print' |
xargs -0n2 mv
नोट: यह फ़ाइल नाम के लिए काम नहीं करेगा जिसमें शामिल हैं \n
।
यह जाहिर है केवल प्रकार से चलता है f
फ़ाइलें ...
केवल नाम संघर्ष फाइलों से होगा में पहले से मौजूद लोक निर्माण विभाग
इस मूल उपसमूह के साथ परीक्षण किया गया
rm -fr junk
rm -f junk*hello*
mkdir -p junk/junkier/junkiest
touch 'hello hello'
touch 'junk/hello hello'
touch 'junk/junkier/hello hello'
touch 'junk/junkier/junkiest/hello hello'
जिसके परिणामस्वरूप
./hello hello
./junk-hello hello
./junk-junkier-hello hello
./junk-junkier-junkiest-hello hello
यहाँ एक ls
संस्करण है .. टिप्पणियाँ स्वागत है। यह इस तरह के अजीब फ़ाइलनाम के लिए काम करता है
"j1ळ\n\001\n/j2/j3/j4/\nh h\n"
, लेकिन मैं वास्तव में किसी भी नुकसान के बारे में जानना चाहता हूं। यह " ls
वास्तव में दुर्भावनापूर्ण रूप से ऐसा कर सकता है ?"
ls -AbQR1p * | # paths in "quoted" \escaped format
sed -n '/":$/,${/.[^/]$/p}' | # skip files in pwd, blank and dir/ lines
{ bwd="$PWD"; while read -n1; # save base dir strip leading "quote
read -r p; do # read path
printf -vs "${p%\"*}" # strip trailing quote"(:)
[[ $p == *: ]] && { # this is a directory
cd "$bwd/$s" # change into new directory
rnp="${s//\//-}"- # relative name prefix
} || mv "$s" "$bwd/$rnp$s"
done; }
बस tr
कमांड के लिए फ़ाइल नाम + पथ को पाइप करें ।tr <replace> <with>
for FILE in `find aaa -name "*.png"`
do
NEWFILE=`echo $FILE | tr '/' '-'`
cp -v $FILE $NEWFILE
done
cp
करने के लिए लाइन बदलना होगा cp -v "$FILE" "$NEWFILE"
? (इसके अलावा, आपको केवल पीएनजी फाइलें नहीं माननी चाहिए।)
cp
लाइन में उद्धरण जोड़ना अपर्याप्त है। लूप के find
साथ पार्सिंग आउटपुट का संपूर्ण दृष्टिकोण for
त्रुटिपूर्ण है। उपयोग करने के लिए केवल सुरक्षित तरीके find
हैं -exec
, या -print0
यदि उपलब्ध हो (कम से कम पोर्टेबल -exec
)। मैं एक और अधिक मजबूत विकल्प का सुझाव देता हूं, लेकिन आपका प्रश्न फिलहाल निर्दिष्ट है।
फ़ाइल नाम में रिक्त स्थान के लिए सुरक्षित:
#!/bin/bash
/bin/find $PWD -type f | while read FILE
do
_new="${FILE//\//-}"
_new="${_new:1}"
#echo $FILE
#echo $_new
/bin/mv "$FILE" "$_new"
done
स्पष्ट कारणों के cp
बजाय के साथ खदान mv
, लेकिन उसी का उत्पादन करना चाहिए।
type find
-> find is /usr/bin/find
मेरी मशीन पर। PATH
एक स्क्रिप्ट में एक चर नाम के रूप में उपयोग करना एक भयानक विचार है। इसके अलावा, आपकी स्क्रिप्ट रिक्त स्थान या बैकस्लैश के साथ नाम दर्ज करती है, क्योंकि आप read
कमांड का दुरुपयोग करते हैं (इस साइट को खोजें IFS read -r
)।
find is hashed (/bin/find)
, प्रासंगिक कैसे? अलग डिस्ट्रॉर्स अलग हैं?
PATH
पर्यावरण चर के बिंदु को याद कर रहे हैं , जो कि हर यूनिक्स प्रणाली का उपयोग करता है। यदि आप लिखते हैं, /bin/find
तो आपकी स्क्रिप्ट वास्तव में हर सिस्टम पर टूटी हुई है (गिल्स, मेरा, और शायद ओपी का) जो नहीं है /bin/find
(जैसे b / c यह है /usr/bin/find
)। PATH
पर्यावरण चर का पूरा बिंदु इसे गैर-मुद्दा बनाना है।
$(pwd)
पहले से ही एक चर में उपलब्ध है $PWD
:। लेकिन आपको यहां एक निरपेक्ष पथ का उपयोग नहीं करना चाहिए : यदि आपकी स्क्रिप्ट को कहा जाता है /home/tim
, तो इसका नाम बदलने /home/tim/some/path
का प्रयास किया जाता है /home-tim-some-path
।