Problem with shift in bash
Tried to use a wrapper around find but hitting the following problem. I want e.g to provide a few directories as arguments but the last argument is always a number that indicates how old data should be removed. For example:
rmoldfiles dir1 dir2 dir3 20
This should remove the old files that are older than 30 days looking at mtime of course
Here is the script:
#!/bin/bash
die()
{
echo >&2 "$@"
exit 1
}
usage()
{
echo >&2 "Usage: $0 [dir1 dir2 dir3] [days old]"
die
}
if [[ (($# < 1)) || -f "$1" ]]; then
if [[ -f "$1" ]]; then
printf '%sn' "Please provide a directory"
fi
usage
fi
while (( $# )); do
while IFS= read -r -d $'' file; do
printf 'rm %sn' "$file"
sleep 1
done < <(find "$1" -type f -mtime +$2 -print0)
shift
done
echo "Done deleting"
Problem
How to shift
directories but not the last argument.
bash shell
add a comment |
Tried to use a wrapper around find but hitting the following problem. I want e.g to provide a few directories as arguments but the last argument is always a number that indicates how old data should be removed. For example:
rmoldfiles dir1 dir2 dir3 20
This should remove the old files that are older than 30 days looking at mtime of course
Here is the script:
#!/bin/bash
die()
{
echo >&2 "$@"
exit 1
}
usage()
{
echo >&2 "Usage: $0 [dir1 dir2 dir3] [days old]"
die
}
if [[ (($# < 1)) || -f "$1" ]]; then
if [[ -f "$1" ]]; then
printf '%sn' "Please provide a directory"
fi
usage
fi
while (( $# )); do
while IFS= read -r -d $'' file; do
printf 'rm %sn' "$file"
sleep 1
done < <(find "$1" -type f -mtime +$2 -print0)
shift
done
echo "Done deleting"
Problem
How to shift
directories but not the last argument.
bash shell
1
Is there a reason that the number of days needs to be the last argument? Could you make it the first argument instead? Or could you make it a switch or flag instead of an argument (and use something likegetopt
to parse arguments/switches/flags)?
– jayhendren
Dec 20 '18 at 18:43
@jayhendren I thought about getopts but I wanted not to overcomplicate this so thought just use"$1" for directories and shift , then use
"$2"` for-mtime
`
– holasz
Dec 20 '18 at 18:47
consider also a simplification of your while find loop:find "$1" -type f -mtime +"$2" -printf rm '%pn' -delete
(assuming GNU find, as per the -print0)
– Jeff Schaller
Dec 20 '18 at 18:56
add a comment |
Tried to use a wrapper around find but hitting the following problem. I want e.g to provide a few directories as arguments but the last argument is always a number that indicates how old data should be removed. For example:
rmoldfiles dir1 dir2 dir3 20
This should remove the old files that are older than 30 days looking at mtime of course
Here is the script:
#!/bin/bash
die()
{
echo >&2 "$@"
exit 1
}
usage()
{
echo >&2 "Usage: $0 [dir1 dir2 dir3] [days old]"
die
}
if [[ (($# < 1)) || -f "$1" ]]; then
if [[ -f "$1" ]]; then
printf '%sn' "Please provide a directory"
fi
usage
fi
while (( $# )); do
while IFS= read -r -d $'' file; do
printf 'rm %sn' "$file"
sleep 1
done < <(find "$1" -type f -mtime +$2 -print0)
shift
done
echo "Done deleting"
Problem
How to shift
directories but not the last argument.
bash shell
Tried to use a wrapper around find but hitting the following problem. I want e.g to provide a few directories as arguments but the last argument is always a number that indicates how old data should be removed. For example:
rmoldfiles dir1 dir2 dir3 20
This should remove the old files that are older than 30 days looking at mtime of course
Here is the script:
#!/bin/bash
die()
{
echo >&2 "$@"
exit 1
}
usage()
{
echo >&2 "Usage: $0 [dir1 dir2 dir3] [days old]"
die
}
if [[ (($# < 1)) || -f "$1" ]]; then
if [[ -f "$1" ]]; then
printf '%sn' "Please provide a directory"
fi
usage
fi
while (( $# )); do
while IFS= read -r -d $'' file; do
printf 'rm %sn' "$file"
sleep 1
done < <(find "$1" -type f -mtime +$2 -print0)
shift
done
echo "Done deleting"
Problem
How to shift
directories but not the last argument.
bash shell
bash shell
edited Dec 20 '18 at 19:08
Rui F Ribeiro
39.7k1479132
39.7k1479132
asked Dec 20 '18 at 18:39
holaszholasz
158212
158212
1
Is there a reason that the number of days needs to be the last argument? Could you make it the first argument instead? Or could you make it a switch or flag instead of an argument (and use something likegetopt
to parse arguments/switches/flags)?
– jayhendren
Dec 20 '18 at 18:43
@jayhendren I thought about getopts but I wanted not to overcomplicate this so thought just use"$1" for directories and shift , then use
"$2"` for-mtime
`
– holasz
Dec 20 '18 at 18:47
consider also a simplification of your while find loop:find "$1" -type f -mtime +"$2" -printf rm '%pn' -delete
(assuming GNU find, as per the -print0)
– Jeff Schaller
Dec 20 '18 at 18:56
add a comment |
1
Is there a reason that the number of days needs to be the last argument? Could you make it the first argument instead? Or could you make it a switch or flag instead of an argument (and use something likegetopt
to parse arguments/switches/flags)?
– jayhendren
Dec 20 '18 at 18:43
@jayhendren I thought about getopts but I wanted not to overcomplicate this so thought just use"$1" for directories and shift , then use
"$2"` for-mtime
`
– holasz
Dec 20 '18 at 18:47
consider also a simplification of your while find loop:find "$1" -type f -mtime +"$2" -printf rm '%pn' -delete
(assuming GNU find, as per the -print0)
– Jeff Schaller
Dec 20 '18 at 18:56
1
1
Is there a reason that the number of days needs to be the last argument? Could you make it the first argument instead? Or could you make it a switch or flag instead of an argument (and use something like
getopt
to parse arguments/switches/flags)?– jayhendren
Dec 20 '18 at 18:43
Is there a reason that the number of days needs to be the last argument? Could you make it the first argument instead? Or could you make it a switch or flag instead of an argument (and use something like
getopt
to parse arguments/switches/flags)?– jayhendren
Dec 20 '18 at 18:43
@jayhendren I thought about getopts but I wanted not to overcomplicate this so thought just use
"$1" for directories and shift , then use
"$2"` for -mtime
`– holasz
Dec 20 '18 at 18:47
@jayhendren I thought about getopts but I wanted not to overcomplicate this so thought just use
"$1" for directories and shift , then use
"$2"` for -mtime
`– holasz
Dec 20 '18 at 18:47
consider also a simplification of your while find loop:
find "$1" -type f -mtime +"$2" -printf rm '%pn' -delete
(assuming GNU find, as per the -print0)– Jeff Schaller
Dec 20 '18 at 18:56
consider also a simplification of your while find loop:
find "$1" -type f -mtime +"$2" -printf rm '%pn' -delete
(assuming GNU find, as per the -print0)– Jeff Schaller
Dec 20 '18 at 18:56
add a comment |
3 Answers
3
active
oldest
votes
A couple of solutions.
Pick out the last command line argument.
args=( "$@" )
num=${args[-1]}
args=( "${args[@]:0:${#args[@]} - 1}" )
(then use
find "${args[@]}" -type f -mtime "+$num" -print -delete
to delete those files).
Put the number first.
num=$1; shift
(then use
find "$@" -type f -mtime "+$num" -print -delete
to delete the files).
The loop is only needed if you have hundreds or thousands of directories to process, in which case the find
command would be too long with a single invocation. Otherwise, don't loop. find
can take multiple search paths.
If you want to insert a delay and use rm
explicitly, and have some formatted output for each file:
find "$@" -type f -mtime "+$num" -exec sh -c '
for pathname do
printf "Removing %sn" "$pathname"
rm -- "$pathname"
sleep 1
done' sh {} +
If you find that you do need to loop over the directories (or if this just feels better):
# Assumes that the arguments are in the order
# num dir1 dir2 dir3 ...
num=$1
shift
for dir do
printf 'Processing %s...n' "$dir"
find "$dir" -type f -mtime "+$num" -exec sh -c '
for pathname do
printf "Removing %sn" "$pathname"
rm -- "$pathname"
sleep 1
done' sh {} +
done
or,
# Assumes that the arguments are in the order
# dir1 dir2 dir3 ... num
args=( "$@" )
num=${args[-1]}
args=( "${args[@]:0:${#args[@]} - 1}" )
for dir in "${args[@]}"; do
# as above
done
Kusalananda where to put this"+$num"
in your last piece of code?
– holasz
Dec 20 '18 at 19:14
@holasz Sorry, the last code snippets assume that you pass the number as the firs argument (because its easiest) and then pick that out into$num
andshift
it off. I'll update after my supper.
– Kusalananda
Dec 20 '18 at 19:17
Kusalandela ok your last code works when using e.grmoldfiles 27 dir1 dir2 dir3 ...
Is there a way to use argument as last dir?
– holasz
Dec 20 '18 at 19:23
@holasz see first part of answer. I'll update soon.
– Kusalananda
Dec 20 '18 at 19:35
@holasz See updated answer.
– Kusalananda
Dec 20 '18 at 19:52
|
show 2 more comments
Since you're only expecting (and providing) three directories before the age parameter, don't loop indiscriminately; instead, loop explicitly:
for dir in 1 2 3; do
# work with "$1"
shift
done
or stop looping when there's one parameter left:
while [ "$#" -gt 1 ]; do
echo "Work with $1"
shift;
done
Since the "days" parameter moves during each shift, you'll need to save it off initially:
days=$4
... before calling the loop.
... and if you allow for an arbitrary number of directories to be passed:
[ "$#" -gt 1 ] || exit 1
days=${@: -1}
while [ "$#" -gt 1 ]; do
echo work with "$1" and "$days"
shift
done
This uses the bash array $@
and asks for the last element of it (indicated by -1
, separated by a space to prevent it from being interpreted as a modifier to :
); it then loops over the parameters one by one until there's one left (the initial 'day' parameter at the end).
There is no limiti. I used 3 dirs as an example but there could be 2 dirs or 5. But if I useshift
this way then$2
isn't having the value that should be passed tomtime
– holasz
Dec 20 '18 at 18:49
I've extended the answer to allow an arbitrary number of directories
– Jeff Schaller
Dec 20 '18 at 18:53
it almost works but$days
are also dragged with the dirs and the script says27 no such file or directory
and the script continues
– holasz
Dec 20 '18 at 19:15
can you show how you called the code? if the "days" value is at the end of the argument list, it won't ever be used inside the loop as a "$1" parameter
– Jeff Schaller
Dec 20 '18 at 19:18
1
Jeff it works now! THank you very much. I learned a lot today!
– holasz
Dec 20 '18 at 19:58
|
show 4 more comments
Just change (( $# ))
to (( $# > 1))
:
while (( $# > 1 )); do
echo "file is: $1"
done
echo "days are: $1"
add a comment |
Your Answer
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "106"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f490178%2fproblem-with-shift-in-bash%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
A couple of solutions.
Pick out the last command line argument.
args=( "$@" )
num=${args[-1]}
args=( "${args[@]:0:${#args[@]} - 1}" )
(then use
find "${args[@]}" -type f -mtime "+$num" -print -delete
to delete those files).
Put the number first.
num=$1; shift
(then use
find "$@" -type f -mtime "+$num" -print -delete
to delete the files).
The loop is only needed if you have hundreds or thousands of directories to process, in which case the find
command would be too long with a single invocation. Otherwise, don't loop. find
can take multiple search paths.
If you want to insert a delay and use rm
explicitly, and have some formatted output for each file:
find "$@" -type f -mtime "+$num" -exec sh -c '
for pathname do
printf "Removing %sn" "$pathname"
rm -- "$pathname"
sleep 1
done' sh {} +
If you find that you do need to loop over the directories (or if this just feels better):
# Assumes that the arguments are in the order
# num dir1 dir2 dir3 ...
num=$1
shift
for dir do
printf 'Processing %s...n' "$dir"
find "$dir" -type f -mtime "+$num" -exec sh -c '
for pathname do
printf "Removing %sn" "$pathname"
rm -- "$pathname"
sleep 1
done' sh {} +
done
or,
# Assumes that the arguments are in the order
# dir1 dir2 dir3 ... num
args=( "$@" )
num=${args[-1]}
args=( "${args[@]:0:${#args[@]} - 1}" )
for dir in "${args[@]}"; do
# as above
done
Kusalananda where to put this"+$num"
in your last piece of code?
– holasz
Dec 20 '18 at 19:14
@holasz Sorry, the last code snippets assume that you pass the number as the firs argument (because its easiest) and then pick that out into$num
andshift
it off. I'll update after my supper.
– Kusalananda
Dec 20 '18 at 19:17
Kusalandela ok your last code works when using e.grmoldfiles 27 dir1 dir2 dir3 ...
Is there a way to use argument as last dir?
– holasz
Dec 20 '18 at 19:23
@holasz see first part of answer. I'll update soon.
– Kusalananda
Dec 20 '18 at 19:35
@holasz See updated answer.
– Kusalananda
Dec 20 '18 at 19:52
|
show 2 more comments
A couple of solutions.
Pick out the last command line argument.
args=( "$@" )
num=${args[-1]}
args=( "${args[@]:0:${#args[@]} - 1}" )
(then use
find "${args[@]}" -type f -mtime "+$num" -print -delete
to delete those files).
Put the number first.
num=$1; shift
(then use
find "$@" -type f -mtime "+$num" -print -delete
to delete the files).
The loop is only needed if you have hundreds or thousands of directories to process, in which case the find
command would be too long with a single invocation. Otherwise, don't loop. find
can take multiple search paths.
If you want to insert a delay and use rm
explicitly, and have some formatted output for each file:
find "$@" -type f -mtime "+$num" -exec sh -c '
for pathname do
printf "Removing %sn" "$pathname"
rm -- "$pathname"
sleep 1
done' sh {} +
If you find that you do need to loop over the directories (or if this just feels better):
# Assumes that the arguments are in the order
# num dir1 dir2 dir3 ...
num=$1
shift
for dir do
printf 'Processing %s...n' "$dir"
find "$dir" -type f -mtime "+$num" -exec sh -c '
for pathname do
printf "Removing %sn" "$pathname"
rm -- "$pathname"
sleep 1
done' sh {} +
done
or,
# Assumes that the arguments are in the order
# dir1 dir2 dir3 ... num
args=( "$@" )
num=${args[-1]}
args=( "${args[@]:0:${#args[@]} - 1}" )
for dir in "${args[@]}"; do
# as above
done
Kusalananda where to put this"+$num"
in your last piece of code?
– holasz
Dec 20 '18 at 19:14
@holasz Sorry, the last code snippets assume that you pass the number as the firs argument (because its easiest) and then pick that out into$num
andshift
it off. I'll update after my supper.
– Kusalananda
Dec 20 '18 at 19:17
Kusalandela ok your last code works when using e.grmoldfiles 27 dir1 dir2 dir3 ...
Is there a way to use argument as last dir?
– holasz
Dec 20 '18 at 19:23
@holasz see first part of answer. I'll update soon.
– Kusalananda
Dec 20 '18 at 19:35
@holasz See updated answer.
– Kusalananda
Dec 20 '18 at 19:52
|
show 2 more comments
A couple of solutions.
Pick out the last command line argument.
args=( "$@" )
num=${args[-1]}
args=( "${args[@]:0:${#args[@]} - 1}" )
(then use
find "${args[@]}" -type f -mtime "+$num" -print -delete
to delete those files).
Put the number first.
num=$1; shift
(then use
find "$@" -type f -mtime "+$num" -print -delete
to delete the files).
The loop is only needed if you have hundreds or thousands of directories to process, in which case the find
command would be too long with a single invocation. Otherwise, don't loop. find
can take multiple search paths.
If you want to insert a delay and use rm
explicitly, and have some formatted output for each file:
find "$@" -type f -mtime "+$num" -exec sh -c '
for pathname do
printf "Removing %sn" "$pathname"
rm -- "$pathname"
sleep 1
done' sh {} +
If you find that you do need to loop over the directories (or if this just feels better):
# Assumes that the arguments are in the order
# num dir1 dir2 dir3 ...
num=$1
shift
for dir do
printf 'Processing %s...n' "$dir"
find "$dir" -type f -mtime "+$num" -exec sh -c '
for pathname do
printf "Removing %sn" "$pathname"
rm -- "$pathname"
sleep 1
done' sh {} +
done
or,
# Assumes that the arguments are in the order
# dir1 dir2 dir3 ... num
args=( "$@" )
num=${args[-1]}
args=( "${args[@]:0:${#args[@]} - 1}" )
for dir in "${args[@]}"; do
# as above
done
A couple of solutions.
Pick out the last command line argument.
args=( "$@" )
num=${args[-1]}
args=( "${args[@]:0:${#args[@]} - 1}" )
(then use
find "${args[@]}" -type f -mtime "+$num" -print -delete
to delete those files).
Put the number first.
num=$1; shift
(then use
find "$@" -type f -mtime "+$num" -print -delete
to delete the files).
The loop is only needed if you have hundreds or thousands of directories to process, in which case the find
command would be too long with a single invocation. Otherwise, don't loop. find
can take multiple search paths.
If you want to insert a delay and use rm
explicitly, and have some formatted output for each file:
find "$@" -type f -mtime "+$num" -exec sh -c '
for pathname do
printf "Removing %sn" "$pathname"
rm -- "$pathname"
sleep 1
done' sh {} +
If you find that you do need to loop over the directories (or if this just feels better):
# Assumes that the arguments are in the order
# num dir1 dir2 dir3 ...
num=$1
shift
for dir do
printf 'Processing %s...n' "$dir"
find "$dir" -type f -mtime "+$num" -exec sh -c '
for pathname do
printf "Removing %sn" "$pathname"
rm -- "$pathname"
sleep 1
done' sh {} +
done
or,
# Assumes that the arguments are in the order
# dir1 dir2 dir3 ... num
args=( "$@" )
num=${args[-1]}
args=( "${args[@]:0:${#args[@]} - 1}" )
for dir in "${args[@]}"; do
# as above
done
edited Dec 20 '18 at 19:52
answered Dec 20 '18 at 18:51
KusalanandaKusalananda
127k16239394
127k16239394
Kusalananda where to put this"+$num"
in your last piece of code?
– holasz
Dec 20 '18 at 19:14
@holasz Sorry, the last code snippets assume that you pass the number as the firs argument (because its easiest) and then pick that out into$num
andshift
it off. I'll update after my supper.
– Kusalananda
Dec 20 '18 at 19:17
Kusalandela ok your last code works when using e.grmoldfiles 27 dir1 dir2 dir3 ...
Is there a way to use argument as last dir?
– holasz
Dec 20 '18 at 19:23
@holasz see first part of answer. I'll update soon.
– Kusalananda
Dec 20 '18 at 19:35
@holasz See updated answer.
– Kusalananda
Dec 20 '18 at 19:52
|
show 2 more comments
Kusalananda where to put this"+$num"
in your last piece of code?
– holasz
Dec 20 '18 at 19:14
@holasz Sorry, the last code snippets assume that you pass the number as the firs argument (because its easiest) and then pick that out into$num
andshift
it off. I'll update after my supper.
– Kusalananda
Dec 20 '18 at 19:17
Kusalandela ok your last code works when using e.grmoldfiles 27 dir1 dir2 dir3 ...
Is there a way to use argument as last dir?
– holasz
Dec 20 '18 at 19:23
@holasz see first part of answer. I'll update soon.
– Kusalananda
Dec 20 '18 at 19:35
@holasz See updated answer.
– Kusalananda
Dec 20 '18 at 19:52
Kusalananda where to put this
"+$num"
in your last piece of code?– holasz
Dec 20 '18 at 19:14
Kusalananda where to put this
"+$num"
in your last piece of code?– holasz
Dec 20 '18 at 19:14
@holasz Sorry, the last code snippets assume that you pass the number as the firs argument (because its easiest) and then pick that out into
$num
and shift
it off. I'll update after my supper.– Kusalananda
Dec 20 '18 at 19:17
@holasz Sorry, the last code snippets assume that you pass the number as the firs argument (because its easiest) and then pick that out into
$num
and shift
it off. I'll update after my supper.– Kusalananda
Dec 20 '18 at 19:17
Kusalandela ok your last code works when using e.g
rmoldfiles 27 dir1 dir2 dir3 ...
Is there a way to use argument as last dir?– holasz
Dec 20 '18 at 19:23
Kusalandela ok your last code works when using e.g
rmoldfiles 27 dir1 dir2 dir3 ...
Is there a way to use argument as last dir?– holasz
Dec 20 '18 at 19:23
@holasz see first part of answer. I'll update soon.
– Kusalananda
Dec 20 '18 at 19:35
@holasz see first part of answer. I'll update soon.
– Kusalananda
Dec 20 '18 at 19:35
@holasz See updated answer.
– Kusalananda
Dec 20 '18 at 19:52
@holasz See updated answer.
– Kusalananda
Dec 20 '18 at 19:52
|
show 2 more comments
Since you're only expecting (and providing) three directories before the age parameter, don't loop indiscriminately; instead, loop explicitly:
for dir in 1 2 3; do
# work with "$1"
shift
done
or stop looping when there's one parameter left:
while [ "$#" -gt 1 ]; do
echo "Work with $1"
shift;
done
Since the "days" parameter moves during each shift, you'll need to save it off initially:
days=$4
... before calling the loop.
... and if you allow for an arbitrary number of directories to be passed:
[ "$#" -gt 1 ] || exit 1
days=${@: -1}
while [ "$#" -gt 1 ]; do
echo work with "$1" and "$days"
shift
done
This uses the bash array $@
and asks for the last element of it (indicated by -1
, separated by a space to prevent it from being interpreted as a modifier to :
); it then loops over the parameters one by one until there's one left (the initial 'day' parameter at the end).
There is no limiti. I used 3 dirs as an example but there could be 2 dirs or 5. But if I useshift
this way then$2
isn't having the value that should be passed tomtime
– holasz
Dec 20 '18 at 18:49
I've extended the answer to allow an arbitrary number of directories
– Jeff Schaller
Dec 20 '18 at 18:53
it almost works but$days
are also dragged with the dirs and the script says27 no such file or directory
and the script continues
– holasz
Dec 20 '18 at 19:15
can you show how you called the code? if the "days" value is at the end of the argument list, it won't ever be used inside the loop as a "$1" parameter
– Jeff Schaller
Dec 20 '18 at 19:18
1
Jeff it works now! THank you very much. I learned a lot today!
– holasz
Dec 20 '18 at 19:58
|
show 4 more comments
Since you're only expecting (and providing) three directories before the age parameter, don't loop indiscriminately; instead, loop explicitly:
for dir in 1 2 3; do
# work with "$1"
shift
done
or stop looping when there's one parameter left:
while [ "$#" -gt 1 ]; do
echo "Work with $1"
shift;
done
Since the "days" parameter moves during each shift, you'll need to save it off initially:
days=$4
... before calling the loop.
... and if you allow for an arbitrary number of directories to be passed:
[ "$#" -gt 1 ] || exit 1
days=${@: -1}
while [ "$#" -gt 1 ]; do
echo work with "$1" and "$days"
shift
done
This uses the bash array $@
and asks for the last element of it (indicated by -1
, separated by a space to prevent it from being interpreted as a modifier to :
); it then loops over the parameters one by one until there's one left (the initial 'day' parameter at the end).
There is no limiti. I used 3 dirs as an example but there could be 2 dirs or 5. But if I useshift
this way then$2
isn't having the value that should be passed tomtime
– holasz
Dec 20 '18 at 18:49
I've extended the answer to allow an arbitrary number of directories
– Jeff Schaller
Dec 20 '18 at 18:53
it almost works but$days
are also dragged with the dirs and the script says27 no such file or directory
and the script continues
– holasz
Dec 20 '18 at 19:15
can you show how you called the code? if the "days" value is at the end of the argument list, it won't ever be used inside the loop as a "$1" parameter
– Jeff Schaller
Dec 20 '18 at 19:18
1
Jeff it works now! THank you very much. I learned a lot today!
– holasz
Dec 20 '18 at 19:58
|
show 4 more comments
Since you're only expecting (and providing) three directories before the age parameter, don't loop indiscriminately; instead, loop explicitly:
for dir in 1 2 3; do
# work with "$1"
shift
done
or stop looping when there's one parameter left:
while [ "$#" -gt 1 ]; do
echo "Work with $1"
shift;
done
Since the "days" parameter moves during each shift, you'll need to save it off initially:
days=$4
... before calling the loop.
... and if you allow for an arbitrary number of directories to be passed:
[ "$#" -gt 1 ] || exit 1
days=${@: -1}
while [ "$#" -gt 1 ]; do
echo work with "$1" and "$days"
shift
done
This uses the bash array $@
and asks for the last element of it (indicated by -1
, separated by a space to prevent it from being interpreted as a modifier to :
); it then loops over the parameters one by one until there's one left (the initial 'day' parameter at the end).
Since you're only expecting (and providing) three directories before the age parameter, don't loop indiscriminately; instead, loop explicitly:
for dir in 1 2 3; do
# work with "$1"
shift
done
or stop looping when there's one parameter left:
while [ "$#" -gt 1 ]; do
echo "Work with $1"
shift;
done
Since the "days" parameter moves during each shift, you'll need to save it off initially:
days=$4
... before calling the loop.
... and if you allow for an arbitrary number of directories to be passed:
[ "$#" -gt 1 ] || exit 1
days=${@: -1}
while [ "$#" -gt 1 ]; do
echo work with "$1" and "$days"
shift
done
This uses the bash array $@
and asks for the last element of it (indicated by -1
, separated by a space to prevent it from being interpreted as a modifier to :
); it then loops over the parameters one by one until there's one left (the initial 'day' parameter at the end).
edited Dec 20 '18 at 19:08
answered Dec 20 '18 at 18:46
Jeff SchallerJeff Schaller
40.6k1056129
40.6k1056129
There is no limiti. I used 3 dirs as an example but there could be 2 dirs or 5. But if I useshift
this way then$2
isn't having the value that should be passed tomtime
– holasz
Dec 20 '18 at 18:49
I've extended the answer to allow an arbitrary number of directories
– Jeff Schaller
Dec 20 '18 at 18:53
it almost works but$days
are also dragged with the dirs and the script says27 no such file or directory
and the script continues
– holasz
Dec 20 '18 at 19:15
can you show how you called the code? if the "days" value is at the end of the argument list, it won't ever be used inside the loop as a "$1" parameter
– Jeff Schaller
Dec 20 '18 at 19:18
1
Jeff it works now! THank you very much. I learned a lot today!
– holasz
Dec 20 '18 at 19:58
|
show 4 more comments
There is no limiti. I used 3 dirs as an example but there could be 2 dirs or 5. But if I useshift
this way then$2
isn't having the value that should be passed tomtime
– holasz
Dec 20 '18 at 18:49
I've extended the answer to allow an arbitrary number of directories
– Jeff Schaller
Dec 20 '18 at 18:53
it almost works but$days
are also dragged with the dirs and the script says27 no such file or directory
and the script continues
– holasz
Dec 20 '18 at 19:15
can you show how you called the code? if the "days" value is at the end of the argument list, it won't ever be used inside the loop as a "$1" parameter
– Jeff Schaller
Dec 20 '18 at 19:18
1
Jeff it works now! THank you very much. I learned a lot today!
– holasz
Dec 20 '18 at 19:58
There is no limiti. I used 3 dirs as an example but there could be 2 dirs or 5. But if I use
shift
this way then $2
isn't having the value that should be passed to mtime
– holasz
Dec 20 '18 at 18:49
There is no limiti. I used 3 dirs as an example but there could be 2 dirs or 5. But if I use
shift
this way then $2
isn't having the value that should be passed to mtime
– holasz
Dec 20 '18 at 18:49
I've extended the answer to allow an arbitrary number of directories
– Jeff Schaller
Dec 20 '18 at 18:53
I've extended the answer to allow an arbitrary number of directories
– Jeff Schaller
Dec 20 '18 at 18:53
it almost works but
$days
are also dragged with the dirs and the script says 27 no such file or directory
and the script continues– holasz
Dec 20 '18 at 19:15
it almost works but
$days
are also dragged with the dirs and the script says 27 no such file or directory
and the script continues– holasz
Dec 20 '18 at 19:15
can you show how you called the code? if the "days" value is at the end of the argument list, it won't ever be used inside the loop as a "$1" parameter
– Jeff Schaller
Dec 20 '18 at 19:18
can you show how you called the code? if the "days" value is at the end of the argument list, it won't ever be used inside the loop as a "$1" parameter
– Jeff Schaller
Dec 20 '18 at 19:18
1
1
Jeff it works now! THank you very much. I learned a lot today!
– holasz
Dec 20 '18 at 19:58
Jeff it works now! THank you very much. I learned a lot today!
– holasz
Dec 20 '18 at 19:58
|
show 4 more comments
Just change (( $# ))
to (( $# > 1))
:
while (( $# > 1 )); do
echo "file is: $1"
done
echo "days are: $1"
add a comment |
Just change (( $# ))
to (( $# > 1))
:
while (( $# > 1 )); do
echo "file is: $1"
done
echo "days are: $1"
add a comment |
Just change (( $# ))
to (( $# > 1))
:
while (( $# > 1 )); do
echo "file is: $1"
done
echo "days are: $1"
Just change (( $# ))
to (( $# > 1))
:
while (( $# > 1 )); do
echo "file is: $1"
done
echo "days are: $1"
answered Dec 20 '18 at 18:47
jayhendrenjayhendren
5,40721444
5,40721444
add a comment |
add a comment |
Thanks for contributing an answer to Unix & Linux Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f490178%2fproblem-with-shift-in-bash%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
Is there a reason that the number of days needs to be the last argument? Could you make it the first argument instead? Or could you make it a switch or flag instead of an argument (and use something like
getopt
to parse arguments/switches/flags)?– jayhendren
Dec 20 '18 at 18:43
@jayhendren I thought about getopts but I wanted not to overcomplicate this so thought just use
"$1" for directories and shift , then use
"$2"` for-mtime
`– holasz
Dec 20 '18 at 18:47
consider also a simplification of your while find loop:
find "$1" -type f -mtime +"$2" -printf rm '%pn' -delete
(assuming GNU find, as per the -print0)– Jeff Schaller
Dec 20 '18 at 18:56