Als ik xargs
gebruik, hoef ik soms niet expliciet de vervangende string te gebruiken:
find . -name "*.txt" | xargs rm -rf
In andere gevallen wil ik de vervangende string specificeren om dingen te doen als:
find . -name "*.txt" | xargs -I '{}' mv '{}' /foo/'{}'.bar
De vorige opdracht verplaatste alle tekstbestanden onder de huidige map naar /foo
en voegt de extensie bar
toe aan alle bestanden.
Als ik in plaats van wat tekst toe te voegen aan de vervangende tekenreeks, die tekenreeks zou willen wijzigen zodat ik wat tekst tussen de naam en de extensie van de bestanden kon invoegen, hoe zou ik dat dan kunnen doen? Laten we bijvoorbeeld zeggen dat ik hetzelfde wil doen als in het vorige voorbeeld, maar de bestanden moeten worden hernoemd/verplaatst van <name>.txt
naar /foo/<name>.bar.txt
(in plaats van /foo/<name>.txt.bar
).
UPDATE: het lukt me een oplossing te vinden:
find . -name "*.txt" | xargs -I{} \
sh -c 'base=$(basename $1) ; name=${base%.*} ; ext=${base##*.} ; \
mv "$1" "foo/${name}.bar.${ext}"' -- {}
Maar ik vraag me af of er een kortere/betere oplossing is.
Antwoord 1, autoriteit 100%
Het volgende commando construeert het move commando met xargs, vervangt het tweede voorkomen van ‘.’ met ‘.bar.’, voert dan de commando’s uit met bash, werkend op mac OSX.
ls *.txt | xargs -I {} echo mv {} foo/{} | sed 's/\./.bar./2' | bash
Antwoord 2, autoriteit 64%
Het is mogelijk om dit in één keer te doen (getest in GNU) zonder het gebruik van tijdelijke variabele toewijzingen
find . -name "*.txt" | xargs -I{} sh -c 'mv "$1" "foo/$(basename ${1%.*}).new.${1##*.}"' -- {}
Antwoord 3, autoriteit 40%
In dit soort gevallen zou een while
-lus beter leesbaar zijn:
find . -name "*.txt" | while IFS= read -r pathname; do
base=$(basename "$pathname"); name=${base%.*}; ext=${base##*.}
mv "$pathname" "foo/${name}.bar.${ext}"
done
Houd er rekening mee dat u bestanden met dezelfde naam in verschillende submappen kunt vinden. Vindt u het goed dat duplicaten worden overschreven door mv
?
Antwoord 4, autoriteit 23%
Als je GNU Parallel http://www.gnu.org/software/parallel/geïnstalleerd, kunt u dit doen:
find . -name "*.txt" | parallel 'ext="{/}" ; mv -- {} foo/{/.}.bar.${ext##*.}'
Bekijk de introductievideo’s voor GNU Parallel voor meer informatie:
https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1
Antwoord 5, autoriteit 4%
Als je iets anders dan bash/sh mag gebruiken, EN dit is alleen voor een mooie “mv”… zou je het eerbiedwaardige “rename.pl”-script kunnen proberen. Ik gebruik het de hele tijd op Linux en cygwin op Windows.
http://people.sc.fsu.edu/~ jburkardt/pl_src/rename/rename.html
rename.pl 's/^(.*?)\.(.*)$/\1-new_stuff_here.\2/' list_of_files_or_glob
Je kunt ook een “-p” parameter gebruiken om de naam van pl te wijzigen, zodat het je vertelt wat het ZOU GEDAAN HEBBEN, zonder het daadwerkelijk te doen.
Ik heb zojuist het volgende geprobeerd in mijn c:/bin (cygwin/windows-omgeving). Ik gebruikte de “-p”, dus het spuugde uit wat het zou hebben gedaan. Dit voorbeeld splitst alleen de basis en extensie en voegt er een string tussen toe.
perl c:/bin/rename.pl -p 's/^(.*?)\.(.*)$/\1-new_stuff_here.\2/' *.bat
rename "here.bat" => "here-new_stuff_here.bat"
rename "htmldecode.bat" => "htmldecode-new_stuff_here.bat"
rename "htmlencode.bat" => "htmlencode-new_stuff_here.bat"
rename "sdiff.bat" => "sdiff-new_stuff_here.bat"
rename "widvars.bat" => "widvars-new_stuff_here.bat"
Antwoord 6, autoriteit 4%
de bestanden moeten worden hernoemd/verplaatst van
<name>.txt
naar/foo/<name>.bar.txt
U kunt het hulpprogramma rename
gebruiken, bijvoorbeeld:
rename s/\.txt$/\.txt\.bar/g *.txt
Hint: de vervangingssyntaxis is vergelijkbaar met sed
of vim
.
Verplaats de bestanden vervolgens naar een doelmap met behulp van mv
:
mkdir /some/path
mv *.bar /some/path
Als u bestanden wilt hernoemen naar submappen op basis van een deel van hun naam, controleert u op:
-p
/--mkpath
/--make-dirs
Maak eventuele niet-bestaande mappen in het doelpad.
Testen:
$ touch {1..5}.txt
$ rename --dry-run "s/.txt$/.txt.bar/g" *.txt
'1.txt' would be renamed to '1.txt.bar'
'2.txt' would be renamed to '2.txt.bar'
'3.txt' would be renamed to '3.txt.bar'
'4.txt' would be renamed to '4.txt.bar'
'5.txt' would be renamed to '5.txt.bar'
Antwoord 7, autoriteit 2%
Daaraan toevoegen is het wikipedia-artikelverrassend informatief
Shell-truc
Een andere manier om een soortgelijk effect te bereiken is om een shell te gebruiken als het gelanceerde commando en om te gaan met de complexiteit in die shell, bijvoorbeeld:
$ mkdir ~/backups
$ find /path -type f -name '*~' -print0 | xargs -0 bash -c 'for filename; do cp -a "$filename" ~/backups; done' bash
Antwoord 8
Geïnspireerd door een antwoord van @justaname hierboven, zal dit commando, dat de one-liner van Perl bevat, het doen:
find ./ -name \*.txt | perl -p -e 's/^(.*\/(.*)\.txt)$/mv $1 .\/foo\/$2.bar.txt/' | bash