Expand bash functions in parameter find exec
How can I make find
my shell set functions and aliases apply inside its exec parameter?
For example, I defined a function similar to bzip2 , but using 7z :
function 7zip () {for f in $ @ ; do ls -alF "$ f"; 7za a -t7z -m0 = lzma -mx = 9 -mfb = 64-md = 64m -ms = on "$ f.7z" "$ f" && & & touch -r "$ f" "$ f.7z" && & & rm -fv "$ f" && & ls -alF "$ f.7z"; made; }
When I push files longer than 7 days to compress:
find . -mtime +7 -name "G*.html" -execdir 7zip {} +
Instead of extending 7zip , no error command was found.
It's all inside a shell script.
source to share
All four commands work fine with function calls. Adjust your search parameters as needed. They all handle spaces in filenames. Personally, I see no point in bypassing another bash instance, but I have included two versions that call bash.
IFS=$'\n'; f=($(find /tmp -maxdepth 1 -name "$USER.*")); f7zipi "${f[@]}"
IFS=; find /tmp -maxdepth 1 -name "$USER.*" | while read -r f ;do f7zipi "$f"; done
IFS=$'\n'; bash -c 'IFS=; f7zipi "$@"' 0 $(find /tmp -maxdepth 1 -name "$USER.*")
find /tmp -maxdepth 1 -name "$USER.*" -exec bash -c 'IFS=; f7zipi "$@"' 0 {} +;
The following is how I configured this feature using GNU bash 4.1.5 on Ubuntu 10.04
BTW. You should use local f
in your function so that you don't come across a calling script variable with the same name.
This is exactly what I added to my ~ / .bashrc
function f7zipi() {
local f
for f in $@; do
ls -alF "$f"
7za a -si -t7z -m0=lzma -mx=9 -mfb=64 \
-md=64m -ms=on "$f.7z" < "$f" &&
touch -r "$f" "$f.7z" &&
rm -fv "$f" &&
ls -alF "$f.7z"
done
}
export -f f7zipi
When I assign the above function in bash terminal command line only, the script runs from that command line, if it calls the function ... If I still apply export -f f7zipi
to the same command line. Then the script succeeds ... However scipt only works for that specific command line session.
When function and export are included ~/bashrc
, the script runs every time in any bash session.
This is a test script
#!/bin/bash
f=/tmp/$USER.abc
g=/tmp/$USER.lmn
rm -fv "$f" "$f".7z
rm -fv "$g" "$g".7z
printf 'abcdefg'>"$f"
printf 'lmnopqr'>"$g"
IFS=$'\n'; f=($(find /tmp -maxdepth 1 -name "$USER.*")); f7zipi "${f[@]}"
exit
source to share
Being an impatient coder than I am, at the moment I changed it to a few lines:
hitlist=$(find . -mtime +7 -name "G*.html")
7zipi $hitlist |awk ' !x[$0]++'
This is the awk bit at the end, by the way, so that the output only prints lines that weren't visible before, so it doesn't clutter with zillion lines:
7-Zip (A) 9.20 Copyright (c) 1999-2010 Igor Pavlov 2010-11-18
p7zip Version 9.20 (locale=en_US.UTF-8,Utf16=on,HugeFiles=on,2 CPUs)
Compressing [Content]
Everything is Ok
NOT really the answer; I still like find to use my macros in general.
source to share
It looks like not everyone find
will accept a function as an argument for --execdir
. It didn't work for me either in original form or with help export -f
.
However, if you inject the script from your function it will work
find . -mtime +7 -name "G*.html" -execdir /path/to/script_7zipi {} +
source to share