15424

pitfalls in renaming files in bash

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

Answer1:

${f// /_}

means: replace all occurences of spaces with underscores

ref

<hr> ${1%/*}

means: remove shortest match of /* from end of string

ref

<hr>
${1##*/}


means: remove longest match of */ from front of string

ref

<hr>

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 <hr>

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

<hr> [ -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

Answer2:

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:

<ol> <li>

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

</li> <li>

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;

</li> <li>

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

</li> <li>

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;

</li> <li>

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);

</li> <li>

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.

</li> </ol>

You can get more information in the initial questions, concerning parameter expansions, from man bash | less -p "Parameter Expansion".

Recommend

  • Combine/Merge Multiple Lines into One Line from a Text File (Powershell)
  • how to read attribute value in json using android
  • Boost split not traversing inside of parenthesis or braces
  • How to write a bison grammer for WDI?
  • Merge strategy for whitespace only changes?
  • Error in .jcall()
  • Detect the cell phone connected to wireless network - C#
  • Splitting on comma outside quotes when escaped quotes exist
  • Is the scope of a variable initialized in a for loop declaration actually more than just block scope
  • AutoComplete Texbox error - write to protected memory
  • Filter log files(_success and _log) in FileSystem.liststatus
  • karma-browserify throws error when trying to load modules shimmed with browserify-shim
  • Assign different values to cell arrays in MATLAB at once
  • Return value syntax in java
  • Find by regex and replace match to lowercase in Bash
  • rails 5 carrierwave no route matches for image
  • Use object spread operator to construct function object with fields
  • MongoDB Compass Visually Insert Sub-Document
  • How to show underscore (shortcut) without holding Alt?
  • In matplotlib, how do you change the fontsize of a single figure?
  • Spring: No transaction manager has been configured
  • Javascript, Regex - I need to grab each section of a string contained in brackets
  • Convert SQLite database to XML
  • accepts_nested_attributes_for practical form use for in Rails 3
  • Object and struct member access and address offset calculation
  • WPF Visiblity Binding to Boolean Expression with multiple Variables
  • Conversion from string “a” to type 'Boolean' is not valid
  • Run Powershell script from inside other Powershell script with dynamic redirection to file
  • Arrays break string types in Julia
  • Load html files in TinyMce
  • How can I get HTML syntax highlighting in my editor for CakePHP?
  • coudnt use logback because of log4j
  • Easiest way to encapsulate a HTML5 webpage into an android app?
  • Busy indicator not showing up in wpf window [duplicate]
  • costura.fody for a dll that references another dll
  • Observable and ngFor in Angular 2
  • How to Embed XSL into XML
  • UserPrincipal.Current returns apppool on IIS
  • Conditional In-Line CSS for IE and Others?
  • java string with new operator and a literal