Skip to main content
added 720 characters in body
Source Link
ilkkachu
  • 147.8k
  • 16
  • 268
  • 441

In the shell:

for f in ./IMG_*.jpg ; do 
    t=${f##*/} 
    touch "$f" -t "${t:4:8}${t:13:4}.${t:17:2}"
done

Bash, ksh, zsh etc have the ${var:n:m} substring expansion, and if you need to do it recursively, enable globstar and use **/IMG_*.jpg instead.

Doing it with find needs the shell, too:

$ find -name "IMG_*.jpg" -exec bash -c '
  for f; do t=${f##*/}; touch "$f" -t "${t:4:8}${t:13:4}.${t:17:2}" ; done
  ' sh {} \+

The first argument to Bash after the script goes to the $0 variable, which usually contains the shell name. The rest go to the positional parameters $1, $2, etc. and for f or for f in "$@" loops over them. The construct is here is rather common (theat least in unix.SE answers). The main part of the loop here is the same as abovein the first example.


The find command in your question find .. -exec touch -t"$(...)" {} \; doesn't work since the command substitution is in double quotes, so it gets expanded before find runs. The {} is piped literally to awk, and it just so happens that the awk script only prints a dot.

If you did put the command substitution in single quotes, it would be passed to touch as-is (find would only substitute {}). touch would get the argument -t$(echo ...), dollar signs, parenthesis and all. find doesn't run the command through the shell by itself, we need to explicitly do it, as above.

In single quotes example:

$ find -name x -exec echo 'hello $(foo {})' \;
hello $(foo ./x)

In the shell:

for f in ./IMG_*.jpg ; do 
    t=${f##*/} 
    touch "$f" -t "${t:4:8}${t:13:4}.${t:17:2}"
done

Bash, ksh, zsh etc have the ${var:n:m} substring expansion, and if you need to do it recursively, enable globstar and use **/IMG_*.jpg instead.

Doing it with find needs the shell, too:

$ find -name "IMG_*.jpg" -exec bash -c '
  for f; do t=${f##*/}; touch "$f" -t "${t:4:8}${t:13:4}.${t:17:2}" ; done
  ' sh {} \+

(the main part of the loop is the same as above)

In the shell:

for f in ./IMG_*.jpg ; do 
    t=${f##*/} 
    touch "$f" -t "${t:4:8}${t:13:4}.${t:17:2}"
done

Bash, ksh, zsh etc have the ${var:n:m} substring expansion, and if you need to do it recursively, enable globstar and use **/IMG_*.jpg instead.

Doing it with find needs the shell, too:

$ find -name "IMG_*.jpg" -exec bash -c '
  for f; do t=${f##*/}; touch "$f" -t "${t:4:8}${t:13:4}.${t:17:2}" ; done
  ' sh {} \+

The first argument to Bash after the script goes to the $0 variable, which usually contains the shell name. The rest go to the positional parameters $1, $2, etc. and for f or for f in "$@" loops over them. The construct is here is rather common (at least in unix.SE answers). The main part of the loop here is the same as in the first example.


The find command in your question find .. -exec touch -t"$(...)" {} \; doesn't work since the command substitution is in double quotes, so it gets expanded before find runs. The {} is piped literally to awk, and it just so happens that the awk script only prints a dot.

If you did put the command substitution in single quotes, it would be passed to touch as-is (find would only substitute {}). touch would get the argument -t$(echo ...), dollar signs, parenthesis and all. find doesn't run the command through the shell by itself, we need to explicitly do it, as above.

In single quotes example:

$ find -name x -exec echo 'hello $(foo {})' \;
hello $(foo ./x)
added 177 characters in body
Source Link
ilkkachu
  • 147.8k
  • 16
  • 268
  • 441

In the shell:

for f in ./IMG_*.jpg ; do 
    t=${f##*/} 
    touch "$f" -t "${t:4:8}${t:13:4}.${t:17:2}"
done

Bash, ksh, zsh etc have the ${var:n:m} substring expansion, and if you need to do it recursively, enable globstar and use **/IMG_*.jpg instead.

Doing it with find needs the shell, too:

$ find -name "IMG_*.jpg" -exec bash -c '
  for f; do t=${f##*/}; touch "$f" -t "${t:4:8}${t:13:4}.${t:17:2}" ; done
  ' sh {} \+

(the main part of the loop is the same as above)

In the shell:

for f in ./IMG_*.jpg ; do 
    t=${f##*/} 
    touch "$f" -t "${t:4:8}${t:13:4}.${t:17:2}"
done

Bash, ksh, zsh etc have the ${var:n:m} substring expansion, and if you need to do it recursively, enable globstar and use **/IMG_*.jpg instead.

In the shell:

for f in ./IMG_*.jpg ; do 
    t=${f##*/} 
    touch "$f" -t "${t:4:8}${t:13:4}.${t:17:2}"
done

Bash, ksh, zsh etc have the ${var:n:m} substring expansion, and if you need to do it recursively, enable globstar and use **/IMG_*.jpg instead.

Doing it with find needs the shell, too:

$ find -name "IMG_*.jpg" -exec bash -c '
  for f; do t=${f##*/}; touch "$f" -t "${t:4:8}${t:13:4}.${t:17:2}" ; done
  ' sh {} \+

(the main part of the loop is the same as above)

added 177 characters in body
Source Link
ilkkachu
  • 147.8k
  • 16
  • 268
  • 441

In the shell?:

for f in ./IMG_*.jpg ; do 
    t=${f##*/} 
    touch "$f" -t "${ft:4:8}${ft:13:4}.${ft:17:2}"
done

Bash, ksh, zsh etc have the ${var:n:m} substring expansion, and if you need to do it recursively, enable globstar and use **/IMG_*.jpg instead.

In the shell?

for f in IMG_*.jpg ; do 
    touch "$f" -t "${f:4:8}${f:13:4}.${f:17:2}"
done

In the shell:

for f in ./IMG_*.jpg ; do 
    t=${f##*/} 
    touch "$f" -t "${t:4:8}${t:13:4}.${t:17:2}"
done

Bash, ksh, zsh etc have the ${var:n:m} substring expansion, and if you need to do it recursively, enable globstar and use **/IMG_*.jpg instead.

Source Link
ilkkachu
  • 147.8k
  • 16
  • 268
  • 441
Loading