Saturday, May 3, 2014

Process Array of Values in Bash Shell

Here's how to iterate over an array of space separated values and process each one separately.

This example takes two file names and runs ls -l on each one.


$ files=(f205707256.java f205708152.java)
$ for file in "${files[@]}"; do
>   echo "$file"
> done
f205707256.java
f205708152.java

$ for file in "${files[@]}"; do   ls -l "$file"; done
-rw-r--r--  1 lex  staff  3685 Apr 28 22:55 f205707256.java
-rw-r--r--  1 lex  staff  2699 Apr 28 22:55 f205708152.java

Bonus Examples


$ for file in "${files[@]}"; do cp "$file" /tmp/; done

$ files=(`find app/models`)
$ for file in "${files[@]}"; do echo "$(basename $file)"; done


Print content of specific file, separate by dashed line

Print git repo's config file, recursing up to two directories

files=(`find . -maxdepth 2 -name \.git -type d`)
for file in "${files[@]}"; do echo "$file";cat $file/config;printf '=%.0s' {1..50};echo ""; done


Print each directory name that is one level down from current directory


dirs=(`find . -maxdepth 1 -type d`) && for dir in "${dirs[@]}"; do echo "$dir"; done


Recursively print every directory name below current directory

This one does not use the for dir idiom.

find . -type d -not -path "\./\.git*" |xargs -n1 -II echo I


Print search text from specific file, 2 directories down

Find each GruntFile.js file and it it has a search string, "livereload:", echo that entire line

files=(`find . -maxdepth 2 -name Gruntfile.js`)
for file in "${files[@]}"; do echo "$file"; grep 'livereload:' "$file"; done


Find Text in Files with same name X levels deep

SRC_FNAME Name of file to search
SRC_TXTText to search for in that file
DIRS_DEEPNumber of directories deep to search

(SRC_FNAME=*.*;SRC_TXT="require.config";DIRS_DEEP=3;files=(`find . -maxdepth $DIRS_DEEP -name "$SRC_FNAME"`);for file in "${files[@]}"; do echo "$file"; grep "$SRC_TXT" "$file"; done)

Get list of file names (no path) of files in some directory


file_list=`find /Users/lex/userconfigs -maxdepth 1 -type f`;for x in $file_list; do echo $(basename $x); done

Strip first 7 characters from directory names, that end in "_Code", only in current directory

Before...

$ for dir in "${dirs[@]}"; do (echo "$dir")  ; done
.
./.idea
./7306OS_01_Code
./7306OS_02_Code
./7306OS_03_Code
./7306OS_04_Code
./7306OS_05_Code
./7306OS_06_Code
./7306OS_07_Code
./7306OS_08_Code
./7306OS_09_Code
./7306OS_10_Code
./7306OS_11_code


Run commands:

$ dirs=(`find . -maxdepth 1 -type d -name "*_Code"`)
$ for dir in "${dirs[@]}"; do (mv "$dir" ${dir:9:8} )  ; done


After...


$ tdml
.
├── 01_Code
│   └── Old
├── 02_Code
│   └── old
├── 03_Code
│   └── old
├── 04_Code
│   ├── chapter4
│   └── old
├── 05_Code
│   ├── controllers
│   ├── server
│   └── views
├── 06_Code
│   ├── __MACOSX
│   ├── controllers
│   ├── helpers
│   ├── old
│   ├── public
│   ├── server
│   └── views
├── 07_Code
│   ├── __MACOSX
│   ├── controllers
│   ├── helpers
│   ├── models
│   ├── mongotest
│   ├── public
│   ├── server
│   └── views
├── 08_Code
├── 09_Code
│   ├── __MACOSX
│   ├── controllers
│   ├── helpers
│   ├── models
│   ├── public
│   ├── server
│   ├── tests
│   └── views
├── 10_Code
│   ├── controllers
│   ├── helpers
│   ├── models
│   ├── public
│   ├── server
│   ├── tests
│   └── views
└── 7306OS_11_code


Change File Extension from "jst.eco" to "tpl" in all subdirectories named "templates"


dirs=(`find . -name templates -type d`);for dir in "${dirs[@]}"; do pushd "$dir" && change-file-ext "jst.eco" "tpl" && popd; done


Process comma separated list or space separated list


$ for X in {a,b,c}; do echo $X; done
a
b
c

$ for X in a b c; do echo $X; done
a
b
c


change-file-ext Script


#!/usr/bin/env ruby

# filename:  change-file-ext
# author:    Lex Sheehan
# copyright: Lex Sheehan LLC
# license:   GPL
# status:    production
# comments:  changes file extensions in current directory

def usage
  puts 'Usage:   change-file-ext  '
  puts 'Example: change-file-ext "css.erb" "css"'
  exit
end

if ARGV.size < 2 || ARGV.include?('--h')
  usage
else
  from_ext = "*.#{ARGV[0]}"
  to_ext = ARGV[1]
end

Dir.glob(from_ext).each{|i| `mv #{i} #{i.slice(0..-from_ext.size)}.#{to_ext}` }


Notes

Previous command now supports wild card searches.

If you customize your terminal colors for use with the grep command, it will make the results even easer to read.



This work is licensed under the Creative Commons Attribution 3.0 Unported License.

No comments:

Post a Comment