pitfalls in renaming files in bash

佐手、 提交于 2020-01-24 19:07:51

问题


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:

  1. 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 /*;

  2. base=${1##*/}

    this deletes the longest matching prefix ##, considering the pattern */; this means that, in x="a/b/c/d", ${x##*/} will give you d;

  3. as pointed before, $1 is the first argument of your script;

  4. 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;

  5. 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, as

    if $file exists, go to the next line, or/otherwise, continue (skip the current iteration of the for loop);

  6. 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!