This question already has answers here:
Looping through directories in Bash
(3 answers)
How to loop over directories in Linux?
(11 answers)
Looping over directories in Bash
(3 answers)
Closed 4 years ago.
I have one directory with 48 sub-directories such like:
output$ ll
total 0
drwxr-sr-x+ 1 xxx 576 Apr 27 16:39 ./
drwxrws---+ 1 xxx 254 May 4 15:12 ../
drwxrws---+ 1 xxx 28 Apr 19 16:31 404904/
drwxrws---+ 1 xxx 28 Apr 19 16:31 404905/
drwxrws---+ 1 xxx 28 Apr 19 16:31 405003/
drwxrws---+ 1 xxx 28 Apr 19 16:31 405050/
drwxrws---+ 1 xxx 28 Apr 19 16:31 405077/
...
I wanted to write a bash for loop to work on some common analysis in them such like:
for d in {404904,404905,405503,...};
do
echo $d
done
My question is how to loop these sub-directories instead of manually type in.
for d in */; do
echo "${d%/}"
done
Related
Is there any way to take away the owner's permission to read a file in macOS? I know there's no reason to do this but I have to for school and I can't find an answer anywhere. Removing my write permission works fine but when I try to remove my read permission it automatically give me my read and write permissions back. As you can see in the console when I use chmod -v -v (extra verbose) it shows the correct permissions it should be changed to but then when checking afterwards they havent changed into that...
thijs#Thijss-MacBook-Air-2 week6 % ls -l
total 16
-rw----r-- 1 thijs staff 12 Oct 11 21:10 greeting.txt
-rw-r--r-- 1 thijs staff 0 Oct 11 21:10 hello.txt
-rw------- 1 thijs staff 15 Oct 11 21:11 weather.txt
thijs#Thijss-MacBook-Air-2 week6 % chmod -v -v u-w weather.txt
weather.txt: 0100600 [-rw------- ] -> 0100400 [-r-------- ]
thijs#Thijss-MacBook-Air-2 week6 % ls -l
total 16
-rw----r-- 1 thijs staff 12 Oct 11 21:10 greeting.txt
-rw-r--r-- 1 thijs staff 0 Oct 11 21:10 hello.txt
-r-------- 1 thijs staff 15 Oct 11 21:11 weather.txt
thijs#Thijss-MacBook-Air-2 week6 % chmod -v -v u-r weather.txt
weather.txt: 0100400 [-r-------- ] -> 0100000 [---------- ]
thijs#Thijss-MacBook-Air-2 week6 % ls -l
total 16
-rw----r-- 1 thijs staff 12 Oct 11 21:10 greeting.txt
-rw-r--r-- 1 thijs staff 0 Oct 11 21:10 hello.txt
-rw------- 1 thijs staff 15 Oct 11 21:11 weather.txt
This question already has answers here:
Sort order in `Dir.entries`
(3 answers)
Closed 4 years ago.
In my /Users/name/website/posts directory I have the following files:
$ ls -la
total 56
5 name staff 160B 16 Apr 20:48 .
3 name staff 96B 16 Apr 20:48 ..
1 name staff 6.5K 16 Apr 20:47 bar.md
1 name staff 11K 16 Apr 20:47 baz.md
1 name staff 4.2K 16 Apr 20:47 foo.md
With this IRB session:
base = "/Users/name/website/posts"
#=> "/Users/bc/website/posts"
entries = Dir.entries(base)
#=> [".", "..", "bar.md", "foo.md", "baz.md"]
How is the order of the returned array determined?
Although specific Ruby implementations may have their specific logic, it is arbitrary from the point of view of the specification.
I am currently sorting the output of ls -l by byte count using:
ls -l | sort -r -k5,5 -n
What if I wanted to make this work with the -# flag? Currently this will output:
-rwxr-xr-x# 1 name staff 7106 2 May 10:43 c
-rwxr-xr-x 1 name staff 675 22 Apr 17:57 a
-rwxr-xr-x 1 name staff 486 23 Apr 07:56 b
drwxr-xr-x 4 name staff 136 25 Apr 18:38 d
-rwxr-xr-x 1 name staff 120 23 Apr 07:59 e
-rwxr-xr-x 1 name staff 112 22 Apr 18:45 g
-rwxr-xr-x 1 name staff 51 22 Apr 18:45 f
total 56
com.apple.metadata:_kMDItemUserTags 42
Where I want it to take the extended attribute keys line and keep it below the appropriate file like so:
-rwxr-xr-x# 1 name staff 7106 2 May 10:43 c
com.apple.metadata:_kMDItemUserTags 42
-rwxr-xr-x 1 name staff 675 22 Apr 17:57 a
-rwxr-xr-x 1 name staff 486 23 Apr 07:56 b
drwxr-xr-x 4 name staff 136 25 Apr 18:38 d
-rwxr-xr-x 1 name staff 120 23 Apr 07:59 e
-rwxr-xr-x 1 name staff 112 22 Apr 18:45 g
-rwxr-xr-x 1 name staff 51 22 Apr 18:45 f
total 56
No need to use sort, just use the -S option with ls
ls -Sl
(that's an upper case S)
I am experimenting with TCL command exec in tclsh and here are my results:
% set show_me_dir "ls"
ls
% exec $show_me_dir
VboxSharedFolder
% set show_me_dir "ls -la"
ls -la
% exec $show_me_dir
couldn't execute "ls -la": no such file or directory
% set show_me_dir {ls -la}
ls -la
% exec $show_me_dir
couldn't execute "ls -la": no such file or directory
% ls -la
total 141
d---------+ 1 wakatana Domain Users 0 Jan 22 19:12 .
d---------+ 1 wakatana Domain Users 0 Apr 16 2014 ..
----------+ 1 wakatana Domain Users 20214 Jan 23 18:43 .bash_history
----------+ 1 wakatana Domain Users 1494 Apr 15 2014 .bash_profile
----------+ 1 wakatana Domain Users 7593 Jan 22 19:03 .bashrc
d---------+ 1 wakatana Domain Users 0 Jan 15 14:56 VboxSharedFolder
%
Can somebody please explain how can I execute command with arguments?
Edit:
The following example from Expanding a list of parameters in Tcl and eval article was big eye opener of what is going on here:
The variable $action is only expanded into the string "piemiddle apple" AFTER the command line has been split into its individual parameters:
% set action {piemiddle apple}
% set $action
can't read "piemiddle apple": no such variable
Result: set command "sees" one argument, equivalent to:
% set {piemiddle apple}
The expand operator allows you to specify that a variable is to be expanded BEFORE the command line is split into individual parameters:
% set action {piemiddle apple}
% set {*}$action
apple
Result: set command "sees" two arguments, equivalent to:
% set piemiddle apple
In earlier versions of Tcl, the eval command was the recommended alternative and it remains available today.
% set action {piemiddle apple}
% eval set $action
apple
Another examples which proves functionality of expansion operator:
% set {*}"name Linus"
Linus
% puts $name
Linus
%
%
% set distro Unbuntu
Unbuntu
% set {*}"linux $distro"
Unbuntu
% puts $linux
Unbuntu
%
%
Finally the discovery that exec needs command as it's first argument and first command option as it's second argument etc.
% exec "ls" "-la"
total 137
d---------+ 1 wakatana Domain Users 0 Jan 22 19:12 .
d---------+ 1 wakatana Domain Users 0 Apr 16 2014 ..
----------+ 1 wakatana Domain Users 20214 Jan 23 18:43 .bash_history
----------+ 1 wakatana Domain Users 1494 Apr 15 2014 .bash_profile
----------+ 1 wakatana Domain Users 7593 Jan 22 19:03 .bashrc
d---------+ 1 wakatana Domain Users 0 Jan 15 14:56 VboxSharedFolder
%
%
% exec "ls -la"
couldn't execute "ls -la": no such file or directory
The safest way to build a command for exec is to use Tcl's list. For example:
% set tcl_version
8.5
% set cmd [list ls -l tmp]
ls -l tmp
% eval exec $cmd
total 32
-rw-r--r-- 1 pynexj staff 1176 Jan 23 23:24 file.txt
-rw-r--r-- 1 pynexj staff 1176 Jan 23 23:24 foo-1.dat
-rw-r--r-- 1 pynexj staff 1176 Jan 23 23:24 foo-2.dat
-rw-r--r-- 1 pynexj staff 1176 Jan 23 23:24 foo-3.dat
% exec {*}$cmd
total 32
-rw-r--r-- 1 pynexj staff 1176 Jan 23 23:24 file.txt
-rw-r--r-- 1 pynexj staff 1176 Jan 23 23:24 foo-1.dat
-rw-r--r-- 1 pynexj staff 1176 Jan 23 23:24 foo-2.dat
-rw-r--r-- 1 pynexj staff 1176 Jan 23 23:24 foo-3.dat
%
Note that {*} is a new syntax of Tcl 8.5 which can help reduce the uses of eval.
As example for ls command you can do:
exec {*}ls -lsa {*}[glob *.cpp]
Please have a look at What does {*} do in TCL?
I know how to delete the files the files which are more than 60 days old. But I have to satisfy below conditions. Please help me to get correct script to automate this.
I have below files for each day on monthly basis. So I have these files for last 3 years.
vtm_data_12month_20140301.txt
vtm_data_12month_20140301.control
vtm_mtd_20130622.txt
vtm_mtd_20130622.control
vtm_ytd_20131031.txtvtm_ytd_20131031.control
I'd like to write a script find the all files which are more than 60 days old and delete them all but except last month file.
Suppose for january I want to keep the last file (latest) vtm_data_12month_20140131.txt and delete all 30 files. Issue here is, there is chance that I might have files received for January 30th, so in that case I should not delete the latest file, but I have to delete the rest.
Please advice me how can we achieve this via shell script. Your response is highly appreciated.
There are many ways to do this. The two primary approaches are either to (1) use the actual file date to determine whether the files are removed or (2) use the date embedded in the filename to determine the file date. Both have advantages and pitfalls. What you seem to be asking is to remove files 60 days older than the latest date embedded in the filename or 2.
As you have indicated, you may have a number of files with dates mixed relatively close to the end and you may need to adjust the date. Rather than just having the script parse for a maximum file date string contained in the file, you can prompt for the end date to measure 60 days back from. Otherwise, just scan each embedded date and find the max, and subtract 60 days from there. The following script prompts for an end_date.
In fact, the following script contains code to remove files by both methods (and sample data). The code to remove based on the actual file create date ( (1) above ) is commented out below the code that uses the embedded date. Look over the script and understand what it does. It is fairly well commented. NOTE the actual rm command is commented out to prevent accidents (even though it requires you to enter YES to confirm removal). Uncomment the rm line to be able to actually remove files. Drop a comment if you have questions:
#!/bin/bash
oifs="$IFS" # save current IFS (internal field separator) (default ' \t\n')
IFS=$'\n' # set IFS to only break on space
## prompt for path containing files & read
printf "\n enter the path to files to remove (no ending '/'): "
read -r rmpath
## validate directory
[ -d "$rmpath" ] || { printf "\nerror: bad path '%s'\n\n" "$rmpath"; exit 1; }
## prompt for ending date of files to keep
printf "\n enter the _end_ date of files to keep 'yyyymmdd' : "
read -r enddatestr
IFS="$oifs" # reset IFS to original
enddt=$(date -d "$enddatestr" +%s) # get enddt in seconds since epoch
enddt=$((enddt - (60 * 24 * 3600))) # subtract 60 days
declare -a rmarray
## Using embedded filename date
mdate=$(date -d "#$enddt" +%Y%m%d) # get mdate string to compare to filename
## fill rmarray with file dates older than mdate
for i in $(find "$rmpath" -maxdepth 1 -type f); do
ffname="${i##*/}" # full filename component
fname=${ffname%.*} # filename w/o extension
fdate="${fname##*_}" # get file date string
## if fdate before mdate, add to remove array
[ "$mdate" -gt "$fdate" ] && rmarray+=( "$i" )
done
# ### Using actual file creation date
# tgtfile=/tmp/tgt_$(date +%s) # tmp filename to measure against
#
# ## create temp file to measure against with find & set trap to remove
# touch -t $(date -d "#${enddt}" +%Y%m%d%H%M.%S) "$tgtfile" &&
# trap 'rm -rf "$tgtfile"' 0
#
# ## fill array with filenames to remove
# rmarray=( $(find "$rmpath" -maxdepth 1 -type f ! -newer $tgtfile) )
## verify files are contained in rmarray
[ "${#rmarray[#]}" -lt 1 ] && {
printf "\n No files matched the dates for removal.\n\n"
exit 1
}
## print files that will be removed
printf "\n ** the following files will be removed **\n\n"
for i in "${rmarray[#]}"; do
ls -al "$i"
done
## prompt for actual removal
printf "\n Continue with ACTUAL removal (YES to remove) : "
read ans
if [ "$ans" = "YES" ]; then
for i in "${rmarray[#]}"; do
# rm "$i" # NOTE: 'rm' is commented, uncomment to really delete
done
else
printf "\n You entered '%s' (not YES), no removal performed.\n\n" "$ans"
fi
exit 0
test directory:
$ls -l dat/fstst
total 0
-rw-r--r-- 1 david david 0 Nov 27 01:10 vtm_data_12month_20140301.control
-rw-r--r-- 1 david david 0 Nov 27 01:10 vtm_data_12month_20140301.txt
-rw-r--r-- 1 david david 0 Nov 27 01:10 vtm_mtd_20130622.control
-rw-r--r-- 1 david david 0 Nov 27 01:10 vtm_mtd_20130622.txt
-rw-r--r-- 1 david david 0 Nov 27 01:10 vtm_ytd_20131031.control
-rw-r--r-- 1 david david 0 Nov 27 01:10 vtm_ytd_20131031.txt
use:
$ bash rmfiles_60days.sh
enter the path to files to remove (no ending '/'): dat/fstst
enter the _end_ date of files to keep 'yyyymmdd' : 20140301
** the following files will be removed **
-rw-r--r-- 1 david david 0 Nov 27 01:10 dat/fstst/vtm_mtd_20130622.txt
-rw-r--r-- 1 david david 0 Nov 27 01:10 dat/fstst/vtm_ytd_20131031.control
-rw-r--r-- 1 david david 0 Nov 27 01:10 dat/fstst/vtm_ytd_20131031.txt
-rw-r--r-- 1 david david 0 Nov 27 01:10 dat/fstst/vtm_mtd_20130622.control
Continue with ACTUAL removal (YES to remove) : YES
result:
$ ls -l dat/fstst
total 0
-rw-r--r-- 1 david david 0 Nov 27 01:10 vtm_data_12month_20140301.control
-rw-r--r-- 1 david david 0 Nov 27 01:10 vtm_data_12month_20140301.txt
The following is an example using the actual file date:
test directory:
$ls -l dat/tst
total 324
-rw-r--r-- 1 david david 74 Sep 9 01:23 1.txt
-rw-r--r-- 1 david david 74 Sep 9 01:23 2.txt
-rw-r--r-- 1 david david 201 Aug 1 03:47 3line.dat
-rw-r--r-- 1 david david 205 Aug 1 03:35 3line.dat.sav
-rw-r--r-- 1 david david 88 Aug 13 04:05 catfile.txt
-rw-r--r-- 1 david david 39 Jul 4 14:40 comma
-rw-r--r-- 1 david david 291 Sep 23 03:00 createfile.txt
-rw-r--r-- 1 david david 11 Jul 17 03:54 data.dat
-rw-r--r-- 1 david david 8 Jul 17 03:54 datb.dat
-rw-r--r-- 1 david david 369 Oct 2 14:25 dia.txt
-rw-r--r-- 1 david david 36 Nov 6 15:51 dicta.dat
-rw-r--r-- 1 david david 23895 Sep 9 17:14 dna.dat
-rw-r--r-- 1 david david 243 Nov 4 23:07 domain.dat
-rw-r--r-- 1 david david 276 Nov 23 00:32 ecread.dat
(snip)
use:
$ bash rmfiles_60days.sh
enter the path to files to remove (no ending '/'): dat/tst
enter the _end_ date of files to keep 'yyyymmdd' : 20141031
** the following files will be removed **
-rw-r--r-- 1 david david 205 Aug 1 03:35 dat/tst/3line.dat.sav
-rw-r--r-- 1 david david 29 Jun 29 02:23 dat/tst/f1f2.dat
-rw-r--r-- 1 david david 8 Jul 17 03:54 dat/tst/datb.dat
-rw-r--r-- 1 david david 60 Jul 27 23:24 dat/tst/vowels.txt
-rw-r--r-- 1 david david 134 Aug 11 00:32 dat/tst/outfile.txt
-rw-r--r-- 1 david david 4622 Jun 26 02:49 dat/tst/single.xml
-rw-r--r-- 1 david david 99 Jul 4 14:51 dat/tst/hostnm
-rw-r--r-- 1 david david 115 Aug 7 01:35 dat/tst/ltags.txt
-rw-r--r-- 1 david david 122 Aug 29 11:11 dat/tst/hh.dat
-rw-r--r-- 1 david david 509 Jul 21 17:28 dat/tst/orders.txt
-rw-r--r-- 1 david david 205 Jun 27 01:06 dat/tst/table.html
(snip)
Continue with ACTUAL removal (YES to remove) : YES
result:
$ ls -l dat/tst
total 168
-rw-r--r-- 1 david david 74 Sep 9 01:23 1.txt
-rw-r--r-- 1 david david 74 Sep 9 01:23 2.txt
-rw-r--r-- 1 david david 291 Sep 23 03:00 createfile.txt
-rw-r--r-- 1 david david 369 Oct 2 14:25 dia.txt
-rw-r--r-- 1 david david 36 Nov 6 15:51 dicta.dat
-rw-r--r-- 1 david david 23895 Sep 9 17:14 dna.dat
-rw-r--r-- 1 david david 243 Nov 4 23:07 domain.dat
-rw-r--r-- 1 david david 276 Nov 23 00:32 ecread.dat
-rw-r--r-- 1 david david 93 Nov 2 21:43 empdata.dat
(snip)