sh - What is the meaning of ${arg##/*/} and {} \; in shell scripting -


please find code below displaying directories in current folder.

  1. what meaning of ${arg##/*/} in shell scripting. (both arg#* , arg##/*/ gives same output. )
  2. what meaning of {} \; in loop statement.
for arg in `find . -type d -exec ls -d {} \;`   echo "output 1" ${arg##/*/}   echo "output 2" ${arg#*} done 

adding @joso's helpful answer:

${arg#*} fundamentally pointless expansion, result identical $arg itself, since strips shortest prefix matching any character (*) , shortest prefix matching character empty string.

${arg##/*/} - stripping longest prefix matching pattern /*/ - useless in context, because output paths ./-prefixed due use of find ., there no prefix starting /. contrast, ${arg##*/} work , strip parent path (leaving folder-name component only).

aside being ill-advised parse command output in for loop, @joso points out, find command in op overly complicated , inefficient (as aside, clarify, find command lists folders in current folder's subtree, not immediate subfolders):

find . -type d -exec ls -d {} \; 

can simplified to:

find . -type d 

the 2 commands same: -exec ls -d {} \; find default anyway (an implied -print).

if put together, get:

find . -mindepth 1 -type d | while read -r arg   echo "folder name: ${arg##*/}"   echo "parent path: ${arg%/*}" done 

note i've used ${arg%/*} second output item, strips shortest suffix matching /* , returns parent path; furthermore, i've added -mindepth 1 find doesn't match .

@joso, in comment, demonstrates solution that's both simpler , more efficient; uses -exec process shell command in-line , + pass many paths possible @ once:

find . -mindepth 1 -type d -exec /bin/sh -c \   'for arg; echo "folder name: ${arg##*/}"; echo "parent: ${arg%/*}"; done' \   -- {} + 

finally, if have gnu find, things easier, can take advantage of -printf primary, supports placeholders things filenames , parent paths:

find . -type d -printf 'folder name: %f\nparen path: %h\n' 

here's bash-only solution based on globbing (pathname expansion), courtesy of @adrian frühwirth:

caveat: requires bash 4+, shell option globstar turned on (shopt -s globstar) - off default.

shopt -s globstar # bash 4+ only: turn on support **  arg in **/  # process directories in entire subtree   echo "folder name: $(basename "$arg")"   echo "parent path: $(dirname "$arg")" done 

note i'm using basename , dirname here parsing, conveniently ignore terminating / glob **/ invariably adds matches.


afterthought re processing find's output in while loop: on off chance filenames contain embedded \n chars, can parse follows, using null char. separate items (see comments why -d $'\0' rather -d '' used):

find . -type d -print0 | while read -d $'\0' -r arg; ... 

Comments

Popular posts from this blog

user interface - How to replace the Python logo in a Tkinter-based Python GUI app? -

objective c - Greedy NSProgressIndicator Allocation -

how to set an OCR language in Google Drive -