I write below statements in my .bashrc
alias ls='ls -l'
$LS = 'ls'
I expected $LS execute ls -l in command line prompt because ls already modified to ls -l. but $LS execute ls only ls.
ls execute ls -l because alias as below:
> ls
total 28
-rw-r--r-- 1 chlee chlee 82 8월 30 22:07 '#test.py#'
drwxr-xr-x 2 chlee chlee 4096 8월 21 04:09 exer
-rw-r--r-- 1 chlee chlee 64 8월 30 21:49 test.py
-rw-r--r-- 1 chlee chlee 49 8월 30 21:47 test.py~
drwxr-xr-x 29 chlee chlee 12288 8월 21 02:51 vsdbg
$LS execute only ls as below:
> $LS
'#test.py#' exer test.py test.py~ vsdbg
How can I get the shell to take into account aliases when variable evaluation?
This should work as you expect:
#!/bin/bash
alias ls="ls -l"
LS () {
ls
}
echo trying lower
ls
echo Trying upper
LS
The function is called LS including parses aliases.
# source LS.sh
trying lower
total 4
-rwxr-xr-x 1 root root 89 Sep 19 21:50 LS.sh
Trying upper
total 4
-rwxr-xr-x 1 root root 89 Sep 19 21:50 LS.sh
Jetchisel was pointing you to this in the comments.
Related
I have the following find command that searches all subdirectories and lists those folders that contain a *.RAR AND a *.MKV file.
find -type d -exec sh -c '[ -f "$0"/*.rar ] && [ -f "$0"/*.mkv ]' '{}' \; -print | sort
What I want to do now is to delete the *.MKV file from those directories.
For example, the above command finds FILEA.RAR and FILEB.MKV and lists the directory as DIRECTORY_CHARLIE. I would like to be able to have the above code, also delete the FILEB.MKV file, well delete the found MKV file from each directory that had both file types.
To start, I've created "_TestDir" with the following subfolders:
#useroneserver ~/files/_TestDir $ ls -all
drwxr-xr-x 2 userone userone 50 Feb 27 19:31 Folder01
drwxr-xr-x 2 userone userone 50 Feb 27 19:32 Folder02
drwxr-xr-x 2 userone userone 50 Feb 27 19:32 Folder03
drwxr-xr-x 2 userone userone 50 Feb 27 19:33 Folder04
drwxr-xr-x 2 userone userone 50 Feb 27 19:34 Folder05
Each folder has 2 files, except Folder03, which only has one file.
userone#remoteserver ~/files/_TestDir $ ls Folder01 -all
drwxr-xr-x 2 userone userone 50 Mar 1 20:03 .
drwxr-xr-x 7 userone userone 105 Feb 27 19:30 ..
-rw-r--r-- 1 userone userone 0 Feb 27 19:31 File1.rar
-rw-r--r-- 1 userone userone 0 Feb 27 19:30 FileA.mkv
userone#remoteserver ~/files/_TestDir $ ls Folder02 -all
drwxr-xr-x 2 userone userone 50 Mar 1 20:04 .
drwxr-xr-x 7 userone userone 105 Feb 27 19:30 ..
-rw-r--r-- 1 userone userone 0 Feb 27 19:32 File2.rar
-rw-r--r-- 1 userone userone 0 Feb 27 19:31 FileB.mkv
userone#remoteserver ~/files/_TestDir $ ls Folder03 -all
drwxr-xr-x 2 userone userone 30 Mar 1 20:04 .
drwxr-xr-x 7 userone userone 105 Feb 27 19:30 ..
-rw-r--r-- 1 userone userone 0 Feb 27 19:32 FileC.mkv
userone#remoteserver ~/files/_TestDir $ ls Folder04 -all
drwxr-xr-x 2 userone userone 50 Mar 1 20:04 .
drwxr-xr-x 7 userone userone 105 Feb 27 19:30 ..
-rw-r--r-- 1 userone userone 0 Feb 27 19:33 File4.rar
-rw-r--r-- 1 userone userone 0 Feb 27 19:33 FileD.mkv
userone#remoteserver ~/files/_TestDir $ ls Folder05 -all
drwxr-xr-x 2 userone userone 50 Mar 1 20:05 .
drwxr-xr-x 7 userone userone 105 Feb 27 19:30 ..
-rw-r--r-- 1 userone userone 0 Feb 27 19:34 File5.rar
-rw-r--r-- 1 userone userone 0 Feb 27 19:33 FileE.mkv
When I run the command in the original post, I get this:
userone#remoteserver ~/files/_TestDir $ find -type d -exec sh -c '[ -f "$0"/*.rar ] && [ -f "$0"/*.mkv ]' '{}' \; -print | sort
./Folder01
./Folder02
./Folder04
./Folder05
That is what I expect to see as the results, since folders 1, 2, 4 & 5 have a file of each of the extensions that I am looking for (*.rar & *.mkv), where as folder 3 only has one *.mkv file.
I have not tried to add any delete function since I have no clue where to start.
What I would like to happen is to be able to remove/delete the following
files:
FileA.mkv from Folder01
FileB.mkv from Folder02
FileD.mkv from Folder04
FileE.mkv from Folder05
Nothing gets deleted from Folder03 since it does not have a .RAR AND a .MKV file, it only has the .MKV. Hope this helps clarify.
Thank you for your assistance.
Regards.
You want to use xargs to run rm which will delete the files.
And define the replacement string, using the -I option of xargs.
Using your directory structure, you can do:
find -type d -exec sh -c '[ -f "$0"/*.rar ] && [ -f "$0"/*.mkv ]' '{}' \; -print | sort | xargs -I % sh -c "rm -f %/File?.mkv"
I took your exact find command, and added this:
| xargs -I % sh -c "rm -f %/File?.mkv"
Explanation
when find runs, it will output
./Folder01
./Folder02
./Folder04
./Folder05
Since xargs is used with the -I % option, it will run the command, replacing % with each directory (like in a loop, one by one). You could use another character than %, but avoid wildcard characters.
The command that xargs will run is sh -c "rm -f %/File?.mkv"
It will therefore do the following commands, in succession:
sh -c "rm -f Folder01/File?.mkv"
sh -c "rm -f Folder02/File?.mkv"
sh -c "rm -f Folder04/File?.mkv"
sh -c "rm -f Folder05/File?.mkv"
Obviously, you can adjust as required.
When I execute the ls -l -h command, I get an output as show by the image below.
How can the number of the items in a folder be included in the output?
Update
The current output looks like this
total 41M
-rw-r--r-- 1 root root 41M Dec 20 09:56 completed_projects.bson
-rw-r--r-- 1 root root 213 Dec 20 09:57 completed_projects.metadata.json
drwxrwxr-x 2 adipster adipster 4.0K Jun 16 13:22 contents
-rw-rw-r-- 1 adipster adipster 13 Jun 16 13:20 file.py
drwxrwxr-x 4 adipster adipster 4.0K Jun 16 13:22 folder
drwxrwxr-x 2 adipster adipster 4.0K Jun 16 13:21 items
But I'll like to have another column indicating the number of items in a folder like this
total 41M
-rw-r--r-- 1 root root 41M Dec 20 09:56 completed_projects.bson
-rw-r--r-- 1 root root 213 Dec 20 09:57 completed_projects.metadata.json
drwxrwxr-x 2 adipster adipster 4.0K Jun 16 13:22 contents 235
-rw-rw-r-- 1 adipster adipster 13 Jun 16 13:20 file.py
drwxrwxr-x 4 adipster adipster 4.0K Jun 16 13:22 folder 19
drwxrwxr-x 2 adipster adipster 4.0K Jun 16 13:21 items 5
where the numbers at the extreme right represents the number of items in a folder
You can do something like this:
echo -n "Number of files in folder is: " && ls | wc -l && ls -l
ouptut should be something like this:
umber of files in folder is: 3
Total 279K
-rwxr-xr-x 1 user users 19K Jun 16 00:17 a
-rwxr-xr-x 1 user users 5K Jun 16 00:17 b
-rwxr-xr-x 1 user users 255K Jun 16 00:17 c
You can omit echo statement, just as a note -n is no new line flag.
sed has an option to execute the constructed replacement with /e.
We only count subdirs, looking at the first character
ls -l | sed -r 's/d(.*) ([^ ]*)/printf "d%s %-20s%s\n" "\1" \2 $(ls \2| wc -l)/e'
EDIT: Solution for directories with spaces in their name.
Parsing ls should be avoided. When you try to fix above cmmand for directory names with spaces, you might try
# Don't do this
ls -l | sed -r 's/d(.{,48}) (.*)/printf "d%s %-20s%s\n" "\1" "\2" $(ls "\2"| wc -l)/e'
It is time to write a script. Perhaps with find or something like
#/bin/bash
for i in *; do
printf "%-70s %s\n" "$(/bin/ls -ld "$i")" "$(/bin/ls -d "$i"/* 2>/dev/null| wc -l)"
done
The wc in the subdir will count wrong when filenames have newlines.
ls() { command ls "$#" | tee >(echo "$(wc -l) items"); }
That uses an output process substitution to run the little "echo" script on its stdin while also displaying stdin (thanks to tee). This way, you don't have to run ls twice.
Usual caveat: output will be incorrect when there's a file with a newline in the name.
Is it possible to write a command that will create a new directory with name passed as argument 'MyFolder' (for example) and will create four files with the same name (as part):
MyFolder.js
MyFolder.css
MyFolder.test.js
README.md
(using mkdir / touch / echo ...)
Main problem - one line command
This one-liner function should do the work:
$ function mkdir_and_files() { mkdir "${1}"; touch ${1}/${1}.js; touch ${1}/${1}.css; touch ${1}/${1}.test.js; touch ${1}/README.md; }; mkdir_and_files "MyFolder" ;
$ ls -latrh MyFolder/
total 0
drwxrwxrwt 15 root wheel 480B Aug 19 18:58 ..
-rw-r--r-- 1 user wheel 0B Aug 19 18:58 MyFolder.js
-rw-r--r-- 1 user wheel 0B Aug 19 18:58 MyFolder.css
-rw-r--r-- 1 user wheel 0B Aug 19 18:58 MyFolder.test.js
-rw-r--r-- 1 user wheel 0B Aug 19 18:58 README.md
drwxr-xr-x 6 user wheel 192B Aug 19 18:58 .
Try this:
populate_dir() { mkdir "$1"; touch "$1/$1".{js,css,test.js} "$1/README.md"; }
populate_dir MyFolder
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?
In this directory when I run
ls -l
it prints the following output:
-rw------- 1 csundl dcsugrad 0 Dec 5 13:51 file3
drwx------ 2 csundl dcsugrad 4096 Dec 5 13:51 Photos
drwx------ 2 csundl dcsugrad 4096 Dec 5 13:51 Pron
drwx------ 2 csunfi dcsugrad 4096 Dec 5 13:51 Spreadsheets
drwx------ 3 csundl dcsugrad 4096 Dec 5 15:12 Stuff
-rwx------ 1 csundl dcsugrad 149 Dec 5 15:08 untitled.sh
The bolded values are the byte sizes (?).
However when I run:
ls -l | wc -c
The total byte size comes up as 340. Why is this?
Thanks.
ls command displays size of the file
but this command:
ls -l | wc -c
counts number of characters in the output of ls command.
To count total size of files in a directory use du command:
du -hs mydir