LinuxQuestions.org
LinuxAnswers - the LQ Linux tutorial section.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
LinkBack Search this Thread
Old 02-24-2010, 07:13 AM   #1
nicolaus2
LQ Newbie
 
Registered: Feb 2010
Posts: 3

Rep: Reputation: 0
bash script to find/change


Hi, guys. Need to write such script, that takes parametrs:
<path> <filter> <string1> [string2]

Script have to find all files in directories and subdirectories, that comply with pattern <filter> and consist the line <string1>. Need to print full path to file and number of the line/lines, where the <string1> was found and count of this lines.

In case if there are [string2], in all founded files need to change <string1> on [string2] with manually confirm of every change.

Any help? Thanks.

Last edited by nicolaus2; 02-24-2010 at 07:16 AM.
 
Old 02-24-2010, 07:25 AM   #2
whizje
Member
 
Registered: Sep 2008
Location: The Netherlands
Distribution: Slackware64 current
Posts: 582

Rep: Reputation: 129Reputation: 129
What do you have already?
 
Old 02-24-2010, 07:49 AM   #3
pixellany
LQ Veteran
 
Registered: Nov 2005
Location: Annapolis, MD
Distribution: Arch/XFCE
Posts: 17,802

Rep: Reputation: 728Reputation: 728Reputation: 728Reputation: 728Reputation: 728Reputation: 728Reputation: 728
Per the LQ Rules, please do not post homework assignments verbatim. We're happy to assist if you have specific questions or have hit a stumbling point, however. Let us know what you've already tried and what references you have used (including class notes, books, and Google searches) and we'll do our best to help. Also, keep in mind that your instructor might also be an LQ member.
 
Old 02-24-2010, 12:44 PM   #4
nicolaus2
LQ Newbie
 
Registered: Feb 2010
Posts: 3

Original Poster
Rep: Reputation: 0
Oh, sorry.

On this step I have specific problems.


With this code I can make a change with manually confirm, but ...
Code:
#!/bin/bash
    PATH_DIR="/home/nick/bash/test1"
    FILTER="*.txt"
    STRING1="asd"
    STRING2="qew"
for file in `find $PATH_DIR -name "$FILTER"` ;
do
    echo "1 Input to make a change"
    echo "2 Input to cancel change"
    read doing
    case $doing in
    1)
    awk '{gsub(/asd/, "qwe",$0); print}' $file >$file.ee
    mv $file.ee $file
    ;;
    2)
    echo continue
    ;;
    esac
    
done
There are some problems:
1. I cann't to pass variables STRING1 and STRING2 into awk. I attempted to do it in many ways, like this
Code:
 awk '{gsub(/st1/, "qwe",$0); print}' st1 = $STRING1 $file >$file.ee
or this
Code:
 awk -v st1="$STRING1" '{gsub(/st1/, "qwe",$0); print}' $file >$file.ee
or this
Code:
 awk -v st1=$STRING1 '{gsub(/st1/, "qwe",$0); print}' $file >$file.ee
2. In those code there is a request (to make a change) in all iterations of for, even if there are no such string in file ... how to ask about the change only in those cases, when the file consists the string?

3. And the main problem: how to print the line, where the string was found? I red much about awk, it functions(match(), index() etc.) but didn't find nothing usefull(
 
Old 02-24-2010, 02:04 PM   #5
tuxdev
Senior Member
 
Registered: Jul 2005
Distribution: Slackware
Posts: 2,008

Rep: Reputation: 110Reputation: 110
Code:
for file in `find $PATH_DIR -name "$FILTER"` ;
This will fail badly. Use this as the basic loop instead:
Code:
while IFS="" read -r -d "" -u 10 file ; do
   ...
done 10< <(find "$path_dir" -name "$filter" -print0)
Also, awk is the wrong tool for the job. you should probably use a combination of grep -n to find the matching line numbers and sed to do the replacements.

Anyhow, throw out the garbage learning material you're using and read this instead:
http://mywiki.wooledge.org/BashGuide
 
Old 02-24-2010, 04:57 PM   #6
nicolaus2
LQ Newbie
 
Registered: Feb 2010
Posts: 3

Original Poster
Rep: Reputation: 0
Heh, thanks a lot, tuxdev. I did it.
 
Old 02-26-2010, 09:50 AM   #7
konsolebox
Senior Member
 
Registered: Oct 2005
Distribution: Gentoo, Slackware, LFS
Posts: 2,242
Blog Entries: 15

Rep: Reputation: 233Reputation: 233Reputation: 233
I just read you email. As per your request I made an update to the code. I hope you'll find this code also helpful to your requirements.

Code:
#!/bin/bash

# fcopy.sh
#
# selectively copies files
#
# usage: [bash|.] fcopy.sh <source directory> <target directory> <ext1, [ext2, ...]>
#

LOG_VERBOSE=false

function log_message {
	echo "fcopy: $1"
}

function log_error {
	message "error: $1" >&2
}

function log_warning {
	message "warning: $1"
}

function log_verbose {
	if [[ $LOG_VERBOSE = true ]]; then
		function log_verbose { echo "fcopy: $1"; }
	else
		function log_verbose { :; }
	fi
	log_verbose "$1"  # doing this might not be safe but it is
}

function show_usage {
	message "usage: $0 -h|--help|-? | [-v|--verbose] <source directory> <target directory> <ext1, [ext2, ...]>"
}

function fail {
	log_error "$1"
	exit 1
}

function check_directory {
	[[ -d $1 ]] || fail "specified $2 $1 does not appear to be directory."
	[[ ! -r $1 || ! -x $1 ]] && fail "specified $2 $1 is not searcheable or changeable."
}

function getabspath {

	# loader-lite-0L.WP20100217.tar.gz @ sf.net/projects/loader

	local -a T1 T2=()
	local -i I=0
	local IFS=/ A

	if [[ $1 == /* ]]; then
		read -a T1 <<< "$1"
	else
		read -a T1 <<< "$PWD/$1"
	fi

	for A in "${T1[@]}"; do
		case "$A" in
		..)
			[[ I -ne 0 ]] && unset T2\[--I\]
			continue
			;;
		.|'\'\'')
			continue
			;;
		esac

		T2[I++]=$A
	done

	if [[ $1 == */ ]]; then
		if [[ I -ne 0 ]]; then
			__="/${T2[*]}/"
		else
			__=/
		fi
	else
		if [[ I -ne 0 ]]; then
			__="/${T2[*]}"
		else
			__=/.
		fi
	fi
}

function main {
	local SOURCEDIR='?' DESTDIR='?' CMD A __

	# parse / check arguments

	for (( ; $#; )); do
		case "$1" in
		-h|--help|-\?)
			show_usage
			exit 1
			;;
		-v|--verbose)
			LOG_VERBOSE=true
			;;
		*)
			if [[ $SOURCEDIR = '?' ]]; then
				SOURCEDIR=$1
			elif [[ $DESTDIR = '?' ]]; then
				DESTDIR=$1
			else
				break
			fi
			;;
		esac

		shift
	done

	if [[ $# -eq 0 ]]; then
		log_error "not enough arguments."
		show_usage
		exit 1
	fi

	# get the absolute paths

	getabspath "$SOURCEDIR/."; SOURCEDIR=$__
	getabspath "$DESTDIR/."; DESTDIR=$__

	# check the extensions

	for A; do
		if [[ $A != [[:alnum:]_] ]]; then  # change this if some characters are also required
			log_warning "extension $A may not be valid."
		fi
	done

	# check the directories, also create destination directory if needed

	check_directory "$SOURCEDIR" "source directory"

	pushd "$SOURCEDIR" || fail "failed to change current working directory to $SOURCEDIR"

	if [[ ! $DESTDIR = /. || -e $DESTDIR ]]; then
		check_directory "$DESTDIR" "destination directory"
	else
		mkdir -p "$DESTDIR" || fail "failed to create destination directory $DESTDIR."
	fi

	# prepare the command

	CMD="find -type f -name '*.$A'"
	shift

	for A; do
		CMD=$CMD" -or -name '*.$A'"
	done

	# copy

	while read -u 3 A; do
		log_verbose "copying $A..."
		cp --parent -v "$A" "$DESTDIR" && continue
		log_warning "failed to copy $A.  press any key to continue.."
		read -s -n 1 -p
	done 3< <(eval exec "$CMD")

	popd  # output pushd and popd may also be redirected to /dev/null

	exit 0
}

( main "$@"; )
old code (http://www.linuxquestions.org/questi...44#post3895444)

Code:
#!/bin/bash

EXTENSIONS="jpg JPG tif TIF bmp BMP psd PSD pdd PDD gif GIF"
SOURCEDIR=/mnt/customer_hd
TARGETDIR=/customer_backups/date_lastname

error() {
   echo "$@"
   exit 1
}

[ "$EXTENSIONS" ] || error "no extensions specified"
[ "${SOURCEDIR}" ] || error "source directory not specified"
[ -d "${SOURCEDIR}" ] || error "source directory not found"
[ "${TARGETDIR}" ] || error "target directory not specified"
[ ! -d $"{TARGETDIR}" ] && mkdir -p ${TARGETDIR}
[ ! -d "${TARGETDIR}" ] || error "target directory creation failed"

pushd "${SOURCEDIR}" || error "can't change directory to source directory"

IFS=$' '
cmd="find -type f | grep"
for a in ${EXTENSIONS}; do cmd="${cmd} -e \.${a}$"; done

IFS=$'\n'
#echo "${cmd}"
for a in $(eval "${cmd}"); do
	cp --parent -v "$a" "${TARGETDIR}"
done

IFS=$' \t\n'
popd
exit 0
p.s. i feel a bit glad (and amazed) knowing that my 3/4-year old posts are still useful to some people. thanks.

btw sorry i haven't tested it yet. please try to fix minor corrections or post back the problem if you find one.

Last edited by konsolebox; 03-15-2010 at 03:06 AM. Reason: synced code from a different thread
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off
Trackbacks are Off
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Search and Replace in bash script daemoneye Other *NIX 1 04-08-2009 01:24 AM
Find and replace with a shell script abefroman Programming 5 03-10-2009 03:38 PM
How do I replace special characters in a string within a bash script? rhaup0317 Linux - Newbie 2 06-03-2008 11:56 AM
find and replace script UnixKiwi Programming 12 04-16-2007 11:08 PM
bash script to replace char in variable gmartin Programming 5 11-08-2004 01:46 PM


All times are GMT -5. The time now is 11:02 AM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration