问题
I am reading a guide here http://mywiki.wooledge.org/BashFAQ/030 on this link a few examples are given I am trying to understand them one example code says
# Bash
# Replace all spaces with underscores
for f in *\ *; do mv -- "$f" "${f// /_}"; done
what I have known till now was use of a backslash for special characters like space of ~ or # etc in case of search and replace
examples or in shell scripts here in above example they have
used ${f// /_}
forward slashes , I am not clear with this is this allowed?
in another example on same page
they give an example to remove space and replace it with underscores
find . -depth -name "* *" -exec bash -c 'dir=${1%/*} base=${1##*/};
mv "$1" "$dir/${base// /_}"' _ {} \;
in above example I am not clear with following
1) dir=${1%/*}
2) base=${1##*/}
3) and when it says mv "$1"
what is meant by $1 in the above statement,
4) finally the find command is being closed with -exec <something> _ {} \;
now what is the use of an underscore _ ,curly braces {} and a backslash followed by a colon above \;?
in the third example they say
# tolower - convert file names to lower case
# POSIX
for file in "$@"do
[ -f "$file" ] || continue # ignore non-existing names
newname=$(echo "$file" | tr '[:upper:]' '[:lower:]') # lower case
[ "$file" = "$newname" ] && continue # nothing to do
[ -f "$newname" ] && continue # don't overwrite existing files
mv -- "$file" "$newname"done
I am not clear with following lines
5) [ -f "$file" ] || continue # ignore non-existing names
I am not clear with [ ] tests the condition if $file exists then what is the use of OR condition || here and the continue statement
6) [ -f "$newname" ] && continue # don't overwrite existing files
same doubt here as in point 5
回答1:
${f// /_}
means: replace all occurences of spaces with underscores
ref
${1%/*}
means: remove shortest match of /*
from end of string
ref
${1##*/}
means: remove longest match of */
from front of string
ref
when it says
mv "$1"
what is meant by $1
$1
is the first positional parameter. So if your script has this
echo $1
and you call like this
foo.sh 111
then output will be
111
finally the find command is being closed with
-exec <something> _ {} \;
now what is the use of an underscore_
, curly braces{}
and a backslash followed by a colon above\;
?
The underscore is a placeholder for parameter $0
ref
The {} \;
idiom is used with find
, to say: run this command once for each file
ref
[ -f "$file" ] || continue
means: if $file
is not a FILE, then continue (immediately end the current iteration of the loop and start the next)
ref
回答2:
For your first question, about the substitution, you have, from man bash
:
${parameter/pattern/string}
Pattern substitution. ... If pattern begins with /, all matches of pattern are replaced with string. Normally only the first match is replaced.
Which means that, ${parameter/pattern/string}
replaces the first occurrence of pattern
in parameter
by string
, where ${parameter//pattern/string}
replaces all of the matchings.
For the second section:
dir=${1%/*}
$1
is the first argument of a script, and may be accessed via itsequivalent${1}
, which allows parameter expansions, such as%...
, that deletes the shortest matching pattern in${1}
, considering the pattern as/*
;base=${1##*/}
this deletes the longest matching prefix
##
, considering the pattern*/
; this means that, inx="a/b/c/d"
,${x##*/}
will give youd
;as pointed before,
$1
is the first argument of your script;the backslash followed by a colon is purely syntax, required to cause
-exec ...
to stop parsing the command line -- to point the end of the command;that's, somehow, quite self contained: you have the condition, an
or
operator, and the second part of the operator, which may be read, in a whole, asif $file exists, go to the next line, or/otherwise, continue (skip the current iteration of the for loop);
as well as you pointed, the case is quite the same, except for the operator, that causes the interpretation, this one time, to be:
if a file named $newname already exists, skip to the next iteration;
another way to read it is
a file named $newname exists AND skips to the next iteration.
You can get more information in the initial questions, concerning parameter expansions, from man bash | less -p "Parameter Expansion"
.
来源:https://stackoverflow.com/questions/15308513/pitfalls-in-renaming-files-in-bash