Viết shell script dùng argument

Chào mọi người,
Mình đang học về hệ điều hành linux.
Mình có bài tập về viết shell script trên linux như sau:

" Write a script modify with the following syntax:

modify [-r] [-l|-u] <dir/file names...>

modify [-r] <sed pattern> <dir/file names...>

modify [-h]

which will modify file names. The script is dedicated to lower-casing ( -l ) file names, upper-casing ( -u ) file names or internally calling sed command with the given sed pattern which will operate on file names. Changes may be done either with recursion ( -r ) or without it.

Write a second script, named modify_examples , which will lead the tester of the modify script through the typical, uncommon and even incorrect scenarios of usage of the modify script. "

Dưới đây là ví dụ: với mỗi syntax -r hay -l, -u sẽ có thay đổi tên thư mục hoặc các file trong thư mục tuỳ theo nhu cầu.




Mình đã tìm được code để viết how hết hoặc viết thường hết các thư mục trong directory hiện tại như ở dưới.
Nhưng không biết làm cách nào để dùng các argument trên đưa vào shell script.
Mong các bạn giúp đỡ.

"for f in *; do mv "$f" "$f.tmp"; mv "$f.tmp" "`echo $f | tr "[:lower:]" "[:upper:]"`"; done"
"for f in *; do mv "$f" "$f.tmp"; mv "$f.tmp" "`echo $f | tr "[:upper:]" "[:lower:]"`"; done

Cậu tham khảo code dưới cho việc lấy argument trong shell script nhé!
Tớ để chừa lại mấy hàm modify cho cậu rồi. Nếu được, cậu implement modify rồi chia sẻ cho mọi người nhé! :slight_smile:

#!/bin/bash

usage() {
    echo "usage: modify.sh [-r] [-l | -u ] <directory>"
    echo "       modify.sh [-r] <sed-command> <directory>"
    echo "          -h  Help"
    echo "          -u  Upper case"
    echo "          -l  Lower case"
    echo "          -r  Recursive"
}

modifyRecursive() {
    local upper=$1
    local lower=$2
    local dir="$3"

    echo "Recursive modification: upper $upper; lower $lower; dir $dir"
}

modifySingle() {
    local upper=$1
    local lower=$2
    local dir="$3"

    echo "Single modification: upper $upper; lower $lower; dir $dir"
}

modifySed() {
    local sedCommand="$1"
    local dir="$2"

    echo "Sed modification: sedCommand $sedCommand; dir $dir"
}

modifyRecursiveSed() {
    local sedCommand="$1"
    local dir="$2"

    echo "Recursive sed modification: sedCommand $sedCommand; dir $dir"
}


doMain() {
    local recursive=0
    local upper=0
    local lower=0
    local sedCommand=''
    local dir=''

    while [ "$1" != "" ]; do
        case $1 in
            -u )     upper=1
                     ;;
            -l )     lower=1
                     ;;
            -r )     recursive=1
                     ;;
            -h )     usage
                     exit
                     ;;
            * )      break
                     ;;
        esac
        shift
    done

    ## Validation
    [ $(($upper + $lower)) -eq 2 ] \
        && echo "Both upper & lower cannot be together." \
        && usage
        && exit 1

    [ $# -eq 0 ] && echo "No directory." \
        && usage
        && exit 1

    [ $# -eq 2 -a $(($upper + $lower)) -eq 1 ] \
        && echo "Upper or lower cannot go with sed command." \
        && usage
        && exit 1


    [ $# -eq 2 ] && sedCommand="$1" \
        && shift

    dir="$1"

    ## Logic goes here
    [ $recursive -eq 0 -a -z "$sedCommand" ] \
        && modifySingle $upper $lower $dir \
        && exit 0

    [ $recursive -eq 1 -a -z "$sedCommand" ] \
        && modifyRecursive $upper $lower $dir \
        && exit 0

    [ $recursive -eq 0 ] \
        && modifySed $sedCommand $dir \
        && exit 0

    modifyRecursiveSed $sedCommand $dir \
        && exit 0
}

doMain $@
6 Likes

Cảm ơn cậu rất nhiều!
Mình muốn hỏi mục đích của đoạn code ##Logic goes here và ý nghĩa của tag -z là gì ạ?

Bạn ơi, mình đang cố đưa các hàm chuyển đổi tên thư mục vào.
Trước nhất mình đang cố hiểu code của bạn bởi khi nộp bài mình sẽ phải vấn đáp nữa.
Khi chạy code với mode -h thì mình nhận được lỗi như này mong bạn chỉ mình sửa với.
Mình rất cảm ơn bạn!

Hi @minh171195,

Cảm ơn cậu về câu hỏi. Có vẻ như cậu thực sự muốn hiểu chương trình ở đây. Đó là điều tốt!


Về các câu hỏi của cậu:

Cậu có thể thấy, ở các dòng code

&& usage

Tớ đã không cho \ vào cuối dòng. Đó là lý do code tớ đưa sẽ không chạy nếu cậu không tìm ra lỗi đó :smile:


Với câu hỏi này:

Cậu nên gọi nó là “flag -z”.
Tớ có để ý thấy cậu dùng Ubuntu. Cậu có thể dễ dàng tìm hiểu flag -z là gì với câu lệnh này:

man test

Về cơ bản, cờ đó kiểm tra xem 1 xâu có độ dài là zero không.


Với câu hỏi này:

Cậu thấy đấy, sau khi nhận được đầu vào và validate nó, cậu mới thực hiện yêu cầu của đề bài. Đó là lý do tớ có ghi comment “logic goes here”.

Tớ hi vọng cậu có đủ thông tin để hoàn thành chương trình. Nó cũng không tới nỗi khó lắm đâu.
Và nhớ, khi nào cậu implement các hàm modify xong, thì share cho tất cả mọi người nhé! :smile:

5 Likes

Hi cậu ơi @library , lại là tớ đây.
Thực sự cảm ơn cậu rất rất nhiều vì đã nhiệt tình giúp đỡ tớ. Nếu không có sự giúp đỡ của cậu thì chắc tớ không biết sẽ bắt đầu ở đâu.
Tớ đã làm được code thay đổi tên của các thư mục theo dạng single và recursive, sed và recursivesed.
Nhưng tớ vẫn còn nhiều câu hỏi nữa để hoàn thiện được bài bởi thứ 6 tớ phải nộp rồi. Hi vọng cậu sẽ giúp tớ.

  1. Khi tớ chạy recursive, tớ đã đảo ngược biến chứa lệnh find để thay đổi các file trong cùng trước, rồi sau đó đến file ngoài và directory. Kết quả đã đúng, nhưng khi chạy xong hay có các chỉ báo về các file trùng nhau và các ký tự không có trong bảng ASCII như là ü, ę,ś, Ô thì không chuyển được, đề bài yêu cầu tớ phải chuyển cả các ký tự này nữa.
./modify2.sh -r -u dir1
mv: cannot stat 'echo': No such file or directory
mv: 'dir1/DIR1_1/GLüCK' and 'dir1/DIR1_1/GLüCK' are the same file
mv: 'dir1/DIR1_1/Gęś' and 'dir1/DIR1_1/Gęś' are the same file
mv: 'dir1/DIR1_1/HÔTEL' and 'dir1/DIR1_1/HÔTEL' are the same file
mv: cannot move 'dir1/DIR1_1' to a subdirectory of itself, 'dir1/DIR1_1/DIR1_1'
  1. Khi chạy single file hay dir thì tất cả kết quả đều đúng, nhưng nếu chạy 2 file cùng lúc hoặc 1 file 1 dir thì sẽ báo vi phạm các Validation mà cậu đã giúp tớ. Tớ muốn hỏi cách để sửa cái này để có thể modify 2 file hoặc 1 file va 1 director cùng một lúc trong tất cả các option bởi đây cũng là một phần của đề bài.
./modify2.sh -u file1 file2
Upper or lower cannot go with sed command.

Dưới đây là code sau khi tớ đã thêm các hàm chỉnh sửa tên.

#!/bin/bash

usage() {
    echo "usage: modify.sh [-r] [-l | -u ] <directory>"
    echo "       modify.sh [-r] <sed-command> <directory>"
    echo "          -h  Help"
    echo "          -u  Upper case"
    echo "          -l  Lower case"
    echo "          -r  Recursive"
}

modifyRecursive() {
    local upper=$1
    local lower=$2
    local dir="$3"
    local a="$(basename "$3")"
    local b="$(dirname "$3")"
		if test $upper -gt $lower
		then	
			list=$(find $dir)
			rev=$(echo "$list" | tac)
			for i in echo $rev
			do 
			modifySingle "1" "0" $i
			done
		elif test $lower -gt $upper 
		then	
			list=$(find $dir)
			rev=$(echo "$list" | tac)
			for i in echo $rev
			do 
			modifySingle "0" "1" $i
			done
		fi	
    #echo "Recursive modification: upper $upper; lower $lower; dir $dir"
}

modifySingle() {
    local upper=$1
    local lower=$2
    local dir="$3"
    local a="$(basename "$3")"
    local b="$(dirname "$3")"
		if test $upper -gt $lower
		then	
			newfile=$(echo "$a" | tr '[:lower:]' '[:upper:]')
			mv -i "$dir" "$b/$newfile"
		elif test $lower -gt $upper 
		then		
			newfile=$(echo "$a" | tr '[:upper:]' '[:lower:]')
			mv -i "$dir" "$b/$newfile"
		fi
	
    #echo "Single modification: upper $upper; lower $lower; dir $dir"
}

modifySed() {
    local sedCommand="$1"
    local dir="$2"
    local a="$(basename "$2")"
    local b="$(dirname "$2")"
                        newfile=$(echo "$a" | sed $sedCommand)
                        mv -i "$dir" "$b/$newfile"
    #echo "Sed modification: sedCommand $sedCommand; dir $dir"
}

modifyRecursiveSed() {
    local sedCommand="$1"
    local dir="$2"
    local a="$(basename "$2")"
    local b="$(dirname "$2")"
    			list=$(find $dir)
			rev=$(echo "$list" | tac)
			for i in echo $rev
			do 
			modifySed $sedCommand $i
			done
    #echo "Recursive sed modification: sedCommand $sedCommand; dir $dir"
}


doMain() {
    local recursive=0
    local upper=0
    local lower=0
    local sedCommand=''
    local dir=''

    while [ "$1" != "" ]; do
        case $1 in
            -u )     upper=1
                     ;;
            -l )     lower=1
                     ;;
            -r )     recursive=1
                     ;;
            -h )     usage
                     exit
                     ;;
            * )      break
                     ;;
        esac
        shift
    done

    ## Validation
    [ $(($upper + $lower)) -eq 2 ] \
        && echo "Both upper & lower cannot be together." \
        && usage \
        && exit 1

    [ $# -eq 0 ] && echo "No directory." \
        && usage \
        && exit 1
    [ $# -eq 2 -a $(($upper + $lower)) -eq 1 ] \
        && echo "Upper or lower cannot go with sed command." \
        && usage \
        && exit 1
    [ $# -eq 2 ] && sedCommand="$1" \
        && shift

    dir="$1"

    ## Logic goes here
    [ $recursive -eq 0 -a -z "$sedCommand" ] \
        && modifySingle $upper $lower $dir \
        && exit 0

    [ $recursive -eq 1 -a -z "$sedCommand" ] \
        && modifyRecursive $upper $lower $dir \
        && exit 0

    [ $recursive -eq 0 ] \
        && modifySed $sedCommand $dir \
        && exit 0

    modifyRecursiveSed $sedCommand $dir \
        && exit 0
}

doMain $@
2 Likes

Hi Minh,

Cho phép tớ trả lời các câu hỏi của cậu :smile:


Với vấn đề này:

Cậu có thể show tớ lỗi cậu gặp được không? Vì những lỗi cậu liệt kê dưới đây không liên quan tới “các ký tự không có trong bảng ASCII như là ü, ę,ś, Ô thì không chuyển được”:


Về vấn đề này:

Với yêu cầu này, cậu cần thay đổi 1 số điểm.

  1. Cậu cần thay đổi validation. Trước validation thứ 2, cậu cần nhận biết parameter đầu tiên có là sed command không.
    ## CHANGE: Extract the sed command
    echo "Random" | sed "$1" > /dev/null 2>&1
    [ $? -eq 0 ] && sedCommand="$1" && shift

    ## Validation
    [ $(($upper + $lower)) -eq 2 ] \
        && echo "Both upper & lower cannot be together." \
        && usage \
        && exit 1

    [ $# -eq 0 ] && echo "No directory." \
        && usage \
        && exit 1

    ## CHANGE: validation condition changes
    [ ! -z "$sedCommand" -a $(($upper + $lower)) -eq 1 ] \
        && echo "Upper or lower cannot go with sed command." \
        && usage \
        && exit 1

   ## CHANGE: Remove the last condition
   
  1. Cậu cần thay thế dir thành directories như thế này
   # Change this
   dir="$1"
   # to this
   directories=$@
  1. Trong các hàm modify, cậu cần thay thế:
# Change
local upper=$1
local lower=$2
local dir="$3"
# to
local upper=$1
local lower=$2
shift
shift
local directories=$@

Tớ hi vọng nó sẽ giúp cậu! :slight_smile:
Nếu cậu gặp khó khăn với việc implement thay đổi trên, cậu có thể hỏi tớ thêm. Tuy nhiên, cậu không nên kỳ vọng là tớ luôn available, vì tớ cũng bận mà :frowning:

5 Likes

Cậu ơi, cảm ơn cậu.
Tớ đã thực hiện sửa code theo hướng dẫn của cậu, và có một số lỗi như sau, khiến tớ muốn hỏi cậu để sửa:

Cậu có thể show tớ lỗi cậu gặp được không? Vì những lỗi cậu liệt kê dưới đây không liên quan tới “ các ký tự không có trong bảng ASCII như là ü, ę,ś, Ô thì không chuyển được ”:

  • Đây không phải là lỗi mà là các ký tự không trong bảng ASCII không bị modify mà chỉ các ký tự trong ASCII bị modify. Tớ muốn hỏi có cách nào để modify cả các ký tự không thuộc ASCII không hả cậu?

Đây là code của tớ sửa để có thể modify được 2 file cùng lúc, hoặc modify được 1 file 1 folder trong cả 4 trường hợp.


usage() {
    echo "usage: modify.sh [-r] [-l | -u ] <directory>"
    echo "       modify.sh [-r] <sed-command> <directory>"
    echo "          -h  Help"
    echo "          -u  Upper case"
    echo "          -l  Lower case"
    echo "          -r  Recursive"
}

modifyRecursive() {
    local upper=$1
    local lower=$2
    shift
    shift
    local directories=$@
    local a="$(basename "$directories")"
    local b="$(dirname "$directories")"
		if test $upper -gt $lower
		then	
			list=$(find $directories)
			rev=$(echo "$list" | tac)
			for i in echo $rev
			do 
			modifySingle "1" "0" $i
			done
		elif test $lower -gt $upper 
		then	
			list=$(find $directories)
			rev=$(echo "$list" | tac)
			for i in echo $rev
			do 
			modifySingle "0" "1" $i
			done
		fi	
    #echo "Recursive modification: upper $upper; lower $lower; dir $dir"
}

modifySingle() {
    local upper=$1
    local lower=$2
    shift
    shift
    local directories=$@
    local a="$(basename "$directories")"
    local b="$(dirname "$directories")"
		if test $upper -gt $lower
		then	
			newfile=$(echo "$a" | tr '[:lower:]' '[:upper:]')
			mv -i "$directories" "$b/$newfile"
		elif test $lower -gt $upper 
		then		
			newfile=$(echo "$a" | tr '[:upper:]' '[:lower:]')
			mv -i "$directories" "$b/$newfile"
		fi
	
    #echo "Single modification: upper $upper; lower $lower; dir $dir"
}

modifySed() {
    local sedCommand="$1"
    shift
    shift
    local directories=$@
    local a="$(basename "$directories")"
    local b="$(dirname "$directories")"
                        newfile=$(echo "$a" | sed $sedCommand)
                        mv -i "$directories" "$b/$newfile"
    #echo "Sed modification: sedCommand $sedCommand; dir $dir"
}

modifyRecursiveSed() {
    local sedCommand="$1"
    shift
    shift
    local directories=$@
    local a="$(basename "$directories")"
    local b="$(dirname "$directories")"
    			list=$(find $directories)
			rev=$(echo "$list" | tac)
			for i in echo $rev
			do 
			modifySed $sedCommand $i
			done
    #echo "Recursive sed modification: sedCommand $sedCommand; dir $dir"
}


doMain() {
    local recursive=0
    local upper=0
    local lower=0
    local sedCommand=''
    local dir=''

    while [ "$1" != "" ]; do
        case $1 in
            -u )     upper=1
                     ;;
            -l )     lower=1
                     ;;
            -r )     recursive=1
                     ;;
            -h )     usage
                     exit
                     ;;
            * )      break
                     ;;
        esac
        shift
    done

    
    echo "Random" | sed "$1" > /dev/null 2>&1
    [ $? -eq 0 ] && sedCommand="$1" && shift
    ## Validation
    [ $(($upper + $lower)) -eq 2 ] \
        && echo "Both upper & lower cannot be together." \
        && usage \
        && exit 1

    [ $# -eq 0 ] && echo "No directory." \
        && usage \
        && exit 1
    [ ! -z "$sedCommand"-a $(($upper + $lower)) -eq 1 ] \
        && echo "Upper or lower cannot go with sed command." \
        && usage \
        && exit 1

    directories=$@

    ## Logic goes here
    [ $recursive -eq 0 -a -z "$sedCommand" ] \
        && modifySingle $upper $lower $directories \
        && exit 0

    [ $recursive -eq 1 -a -z "$sedCommand" ] \
        && modifyRecursive $upper $lower $directories \
        && exit 0

    [ $recursive -eq 0 ] \
        && modifySed $sedCommand $directories \
        && exit 0

    modifyRecursiveSed $sedCommand $directories \
        && exit 0
}

doMain $@
  • Ban đầu tớ định bỏ vần Validation đi vì đề bài không yêu cầu, với lại sợ vấn đáp bị hỏi đến mà lúng túng. Nhưng khi bỏ đi thì tớ thấy không chạy được đúng nữa, không biết vì sao. (có lẽ do thiếu command shift)
  • Phần sed sau khi tớ sửa các biến local theo kiểu mới thì cũng không chạy ra đúng nữa. Chỉ có single và res cho 1 file hoặc 1 dir thì đã đúng. Còn lại phần sed và ressed đều không chạy được nữa.
  • Khi tớ thử modify 2 file hoặc 1 file 1 directory thì vẫn chưa chạy được mà bị báo lỗi như này:
./modify3.sh -u file1 file2
./modify3.sh: line 126: [: too many arguments
mv: cannot stat 'file1 file2': No such file or directory
  • Ngoài ra, còn một example nữa về việc modify dir1/* thì chỉ modify các file và folder con thôi, chứ không modify folder dir1 thì tớ vẫn đang tìm cách. Một lần nữa, cảm ơn cậu!
1 Like

Hi cậu,

Có lẽ là cậu đang đi quá nhanh, mà bỏ qua việc tìm hiểu cặn kẽ các đoạn code rồi.
Tớ nghĩ chúng ta nên đi chậm lại chút.
Tớ sẽ đặt cho cậu 1 số câu hỏi và đưa ra 1 số suggestion quan trọng, mục đích để cậu hiểu thêm về code + tổ chức lại kiến thức của cậu, trước khi đi xa hơn. Với các câu hỏi dưới đây, tớ sẽ không chấp nhận câu trả lời là “không biết” (đừng lo quá, tớ sẽ hỏi đủ đơn giản để cậu có thể tự tìm câu trả lời, vì mục đích của tớ là để cậu tự tìm hiểu những gì xảy ra trong code).

  • [Question] biến $@ là gì?
  • [Question] Tại sao 2 dòng dưới đây lại sai?
    local a="$(basename "$directories")"
    local b="$(dirname "$directories")"

Thêm suggestion nho nhỏ, cậu nên đổi tiên biến đi nha, không sau này lúc cậu cần tìm biến a, cậu sẽ ngạc nhiên về số lượng kết quả trả về đó :wink:

  • [Suggestion] Khi tớ hỏi về lỗi cậu gặp phải, cậu nên nêu ra thông tin theo mẫu thế này:

Description: ghi ngắn gọn mô tả lỗi của cậu
Input: đầu vào gây ra lỗi của cậu
Expected output: đầu ra kỳ vọng của cậu
Actual output: đầu ra thực tế

Tớ sẽ không thể giúp cậu nếu như cậu không đưa ra bất kỳ thông tin gì, ví dụ như message lỗi (nếu không, tất cả chỉ là phỏng đoán, và tớ không làm việc trên phỏng đoán).

  • [Suggestion] Tớ đưa cậu đoạn code trên, nó sẽ là của cậu nếu như cậu hiểu nó cặn kẽ như tớ. Như tớ đang thấy, cậu đang nóng lòng muốn chạy xong chương trình trước khi bỏ công ra tìm hiểu. Việc đó sẽ khiến cậu phụ thuộc vào tớ rất nhiều, vì tớ có vẻ như là người duy nhất hiểu chuyện gì đang xảy ra ở đây.
    Vậy nên, cậu thử cố gắng hiểu hết những gì đoạn code tớ đưa cho cậu trước khi implement nhé! :smile:

Tớ chờ phản hồi của cậu.

4 Likes

Hi @library,

Đúng là tớ hơi vội thật, cảm ơn cậu đã giúp tớ hiểu cặn kẽ hơn về các đoạn code. Sau 2 hôm, tớ đã khá tự tin để trả lời các câu hỏi của cậu bởi nhờ đó mà tớ đã hoàn thiện được bài tập này.
Cảm ơn cậu rất nhiều vì đã giúp tớ làm được bài tập này, hết bài này tớ lại có một bài code C nữa :sob: sự học thật gian nan.
Dưới đây là phần code của tớ, tuy nhiên vẫn có một vài phần tớ muốn hoàn thiện hơn, nên tớ muốn hỏi cậu mấy chỗ:

  • Khi tớ chạy ./modify.sh -u dir1/*
    Tớ mong tất cả những file, thư mục con, file trong thư mục con sẽ được viết hoa.
    Nhưng chỉ có thư mục con và file được viết hoa thôi, còn file trong thư mục con vẫn giữ nguyên.
  • Khi tớ chạy ./modify.sh -r -u dir1
    Tớ mong tất cả các ký tự các file ở trong đều được viết hoa, nhưng thực tế lại không được như vậy.
    Expected output:

gęś Glück HÔTEL -> GĘŚ GLÜCK HÔTEL

Actual output:

gęś Glück HÔTEL -> Gęś GLüCK HÔTEL

  • Khi tớ lấy directories cho phần sed, thì argument đầu tiên lúc nào cũng là sedCommand, vậy nên khi chạy vòng lặp trên directories khiến một vài lỗi gây khó chịu hiện lên là không tìm được file tên như là sedCommand. Tớ muốn hỏi làm thế nào để lấy các argument mà loại đi argument đầu tiên để đỡ bị những lỗi như này hiện lên nữa.

/modify3.sh -r ‘s/ile/ale/g’ file1 dir1
find: ‘s/ile/ale/g’: No such file or directory
find: ‘s/ile/ale/g’: No such file or directory
mv: cannot stat ‘s/ile/ale/g’: No such file or directory

Đây là code tớ đã làm được 95% đề bài rùi :smile: :

#!/bin/bash

usage() {
    echo "usage: modify.sh [-r] [-l | -u ] <directory>"
    echo "       modify.sh [-r] <sed-command> <directory>"
    echo "          -h  Help"
    echo "          -u  Upper case"
    echo "          -l  Lower case"
    echo "          -r  Recursive"
}

modifyRecursive() {
    local upper=$1
    local lower=$2
    shift
    shift
    local directories="$@"
		if test $upper -gt $lower
		then	
			for i in $directories
			do
			list=$(find $i)
			rev=$(echo "$list" | tac)
				for i in echo $rev
				do 
				modifySingle "1" "0" $i
				done
			done
		elif test $lower -gt $upper 
		then	
			for i in $directories
			do
			list=$(find $i)
			rev=$(echo "$list" | tac)
				for i in echo $rev
				do 
				modifySingle "0" "1" $i
				done
			done
		fi
}

modifySingle() {
    local upper=$1
    local lower=$2
    shift
    shift
    local directories="$@"
		if test $upper -gt $lower
		then	
			for i in $directories
			do
			base_name="$(basename $i)"
			dir_name="$(dirname $i)"
			newfile=$(echo "$base_name" | tr '[:lower:]' '[:upper:]')
			mv -i $i "$dir_name/$newfile"
			echo "Single modification: upper $upper; lower $lower; dir $i"
			done
		elif test $lower -gt $upper 
		then		
			for i in $directories
			do
			base_name="$(basename $i)"
			dir_name="$(dirname $i)"
			newfile=$(echo "$base_name" | tr '[:upper:]' '[:lower:]')
			mv -i $i "$dir_name/$newfile"
			echo "Single modification: upper $upper; lower $lower; dir $i"
			done
		fi
}

modifySed() {
    local sedCommand="$1"
    local directories="$@"
   			for i in $directories
			do
			base_name="$(basename $i)"
			dir_name="$(dirname $i)"
                        newfile=$(echo "$base_name" | sed $sedCommand)
                        mv -i $i "$dir_name/$newfile"
 			echo "Sed modification: sedCommand $sedCommand; dir $i"
			done
}

modifyRecursiveSed() {
    local sedCommand=$1
    local directories="$@"
    			list=$(find $directories)
			rev=$(echo "$list" | tac)
			for i in echo $rev
			do 
			modifySed $sedCommand $i
			echo "Recursive sed modification: sedCommand $sedCommand; dir $i"
			done
}


doMain() {
    local recursive=0
    local upper=0
    local lower=0
    #echo $1
    #echo $2
    #echo $3
    #echo $@
    while [ "$1" != "" ]; do
        case $1 in
            -u )     upper=1
                     ;;
            -l )     lower=1
                     ;;
            -r )     recursive=1
                     ;;
            -h )     usage
                     exit
                     ;;
            * )      break
                     ;;
        esac
        shift
    done

    #[ $# -ge 2 ] && sedCommand="$1" \
    #    && shift

    directories=$@

    ## Logic goes here
    [ $recursive -eq 0 -a "$upper" != "$lower" ] \
        && modifySingle $upper $lower $directories \
        && exit 0

    [ $recursive -eq 1 -a "$upper" != "$lower" ] \
        && modifyRecursive $upper $lower $directories \
        && exit 0

    [ $recursive -eq 0 ] \
        && modifySed $1 $directories \
        && exit 0

    modifyRecursiveSed $1 $directories \
        && exit 0
}

doMain $@
2 Likes

Hi cậu,

Nice work! Tớ nghĩ cậu đã học được rất nhiều qua assignment này rồi :smiley:
Về các câu hỏi của cậu, tớ sẽ trả lời nhanh trước 1 số câu tớ đã thấy. Những câu hỏi khác tớ sẽ trả lời cậu sau khi tớ đọc kỹ code của cậu hơn.


Về vấn đề này:

Đây là vấn đề về locale.

The LC_CTYPE category does not support multicharacter elements. For example, the German sharp-s character is traditionally classified as a lowercase letter. There is no corresponding uppercase letter; in proper capitalization of German text, the sharp-s character is replaced by the two characters ss. This kind of conversion is outside of the scope of the toupper and tolower keywords.

Cậu chỉ cần set lại locale của cậu đúng trước khi gọi tr là sẽ convert được.
Tớ không nhớ rõ locale của tiếng Đức là gì, tuy nhiên, tớ đã thử convert ví dụ của cậu trên máy tớ, và nó chạy như kỳ vọng.

➜  ~ locale
LANG=""
LC_COLLATE="C"
LC_CTYPE="UTF-8"
LC_MESSAGES="C"
LC_MONETARY="C"
LC_NUMERIC="C"
LC_TIME="C"
LC_ALL=
➜  ~ echo "gęś Glück HÔTEL" | tr '[:lower:]' '[:upper:]'
GĘŚ GLÜCK HÔTEL

Cậu có thể set locale giống máy tớ và chạy thử :smiley: Nếu tớ không nhầm, chỉ cần LC_CTYPE là đủ.

LC_CTYPE="UTF-8" echo "gęś Glück HÔTEL" | tr '[:lower:]' '[:upper:]'

Về vấn đề này:

Lý do cho việc này là do hàm modifyRecursive được gọi thay cho modifyRecursiveSed.

Tớ có chỉ cho cậu cách nhận biết sedCommand ở comment trước rồi. Cậu thêm đoạn code này trước validation part nhé!

    ## CHANGE: Extract the sed command
    echo "Random" | sed "$1" > /dev/null 2>&1
    [ $? -eq 0 ] && sedCommand="$1" && shift

Dòng đó giúp cậu nhận biết đâu là sedCommand.

Cậu cũng thay đổi mất các condition của từng hàm modify rồi.
Để code của cậu chạy, cậu cần bỏ comment code đó và khôi phục lại các điều kiện ở phần logic goes here mà tớ đã viết ban đầu (đừng dùng $1 thay cho $sedCommand nhé!):

    ## Logic goes here
   [ $recursive -eq 0 -a -z "$sedCommand" ] \
        && modifySingle $upper $lower $directories \
        && exit 0

    [ $recursive -eq 1 -a -z "$sedCommand" ] \
        && modifyRecursive $upper $lower $directories \
        && exit 0

    [ $recursive -eq 0 ] \
        && modifySed $sedCommand $directories \
        && exit 0

    modifyRecursiveSed $sedCommand $directories \
        && exit 0

Tớ sẽ trả lời câu hỏi còn lại sau khi đọc kỹ code của cậu.

3 Likes

Hi @minh171195

Về câu hỏi này của cậu:

Nếu cậu mong “tất cả những file, thư mục con, file trong thư mục con sẽ được viết hoa”, tớ nghĩ đó là behavior của flag -r, phải không? :smiley:
Tớ nghĩ với ./modify.sh -u dir1/*, thư mục con và file được viết hoa, còn file trong thư mục con giữ nguyên, là expected behavior.

# Before
.
├── dir1
│   ├── dir1_1
│   │   └── hotel
│   ├── file1
│   └── file2
└── modify.sh

# After
.
├── dir1
│   ├── DIR1_1
│   │   └── hotel
│   ├── FILE1
│   └── FILE2
└── modify.sh
2 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?