i am trying to get the info of the latest folder created in a particular path.
Here i am using the below command to fetch and filter the results so that i get only folders starting with 11,12,19:
ls_info=$(ls -lrt /orcl/grid/product |grep '11\|12\|19')
The output of ls_info is :
total 12
drwxrwx--- 3 oragrid oinstall 4096 May 21 2014 11.2.0.3
drwxr-xr-x 3 oragrid oinstall 4096 Feb 25 2019 11.2.0.4
How can i fetch "11.2.0.4" from this,which is the latest created folder.
Please suggest.Thanks.
Do not parse ls. Use find instead. First get the list of directories you want and print the directories with the modification timestamps. Then sort the list, filter newest line and remove the timestamp. With GNU utilities you can:
find /orcl/grid/product -mindepth 1 -maxdepth 1 -type d '(' -name '11*' -o -name '12*' -o -name '19*' ')' -printf "%Ts\t%f\n" | sort -n | cut -f2- | tail -n1
Related
I have a folder with some 500k subfolders - and I would like to find the last directory which was added to this folder. I am having to do this due to a power failure issue :(
I dont excatly know when the power failed, so using this:
find . -type d -mmin -360 -print
which I beleive is the last 360 minutes? However, gives me results which I am not exactly sure of.
Shortly speaking, I would like to get the last directory which was created within this folder.
Any pointers would be great.
Suggesting :
find . -type d -printf "%C# %p\n" |sort -n|tail -n1|awk '{print $2}'
Explanation:
find . -type d -printf "%C# %p\n"
find . start searching from current directory recursively
-type d search only directory files
-printf "%C# %p\n" for each directory print its last change time in secs from Unix epoch time including sec fraction, followed by file name with path.
For example: 1648051886.4404644000 /tmp/mc-dudi
|sort -n|tail -n1
Sort the result from find as numbers, and print the last row.
awk '{print $2}'
From last row, print only second field
You might try this: it shows your last modification date/time in a sortable manner, and by sorting it, the last entry should be the most recent one:
find ./ -exec ls -dils --time-style=long-iso {} \; | sort -k8,9
Edit: and specific for directories:
find ./ -type d -exec ls -dils --time-style=long-iso {} \; | sort -k8,9
Assuming you're using a file system that tracks file creation ('birth' is the usual terminology) times, and GNU versions of the programs used below:
find . -type d -exec stat --printf '%W\t%n\0' \{\} + | sort -z -k1,1nr | head -1 -z | cut -f 2-
This will find all subdirectories of the current working directory, and for each one, print its birth time (The %W format field for stat(1)) and name (The %n format). Those entries are then sorted based on the timestamp, newest first, and the first line is returned minus the timestamp.
Unfortunately, GNU find's -printf doesn't support birth times, so it calls out to stat(1) to get those, using the multi-argument version of -exec to minimize the number of instances of the program that need to be run. The rest is straightforward sorting of a column, using 0-byte terminators instead of newlines to robustly handle filenames with newlines or other funky characters in them.
Mantaining a symbolic link to the last known subdirectory could avoid listing all of them to find the latest one.
ls -dl $(readlink ~/tmp/last_dir)
drwxr-xr-x 2 lmc users 4096 Jan 13 13:20 /home/lmc/Documents/some_dir
Find newer ones
ls -ldt $(find -L . -newer ~/tmp/last_dir -type d ! -path .)
drwxr-xr-x 2 lmc users 6 Mar 1 00:00 ./dir2
drwxr-xr-x 2 lmc users 6 Feb 1 00:00 ./dir1
Or
ls -ldt $(find -L . -newer ~/tmp/last_dir -type d ! -path .) | head -n 1
drwxr-xr-x 2 lmc users 6 Mar 1 00:00 ./dir2
Don't use the chosen answer if you really want to find the last created sub-directory
According to the question:
Directories should be sorted by creation time instead of modification time.
find --mindepth 1 is necessary because we want to search only sub-directories.
Here are 2 solutions that both fulfill the 2 requirements:
GNU
find . -mindepth 1 -type d -exec stat -c '%W %n' '{}' '+' |
sort -nr | head -n1
BSD
find . -mindepth 1 -type d -exec stat -f '%B %N' '{}' '+' |
sort -nr | head -n1
I'm trying to compose a command/function to list any directory displaying the files with the following rules, from top level to deepest level:
hidden files
directories
alphabetically
Another feature I want to grant is to be able to use the command/function for a passed directory. Example:
Goal
Basically I'd like to input something like:
user#machine:cuur-path $ my_listing_magic /some/crazy/directory
and get an output looking like:
drwxrwxr-x 6 User Group 4,0K abr 8 12:12 .aaa_dir/
drwxrwxr-x 3 User Group 4,0K abr 8 12:12 .bbb_dir/
drwxrwxr-x 3 User Group 4,0K out 14 2020 .ccc_dir/
-rw-rw-r-- 1 User Group 4,1K abr 12 17:44 .a_file
-rw-r--r-- 1 User Group 25 dez 4 2017 .b_file
-rw-rw-r-- 1 User Group 21 mai 20 15:50 .c_file
drwx------ 44 User Group 4,0K mai 27 16:44 ddd_dir/
drwx------ 3 User Group 4,0K abr 5 2018 eee_dir/
drwx------ 3 User Group 4,0K abr 5 2018 fff_dir/
-rw-r--r-- 1 User Group 4,8K jun 1 18:52 d_file
-rw-r--r-- 1 User Group 1,2K jun 1 19:42 e_file
-rw------- 1 User Group 106K jun 1 19:33 f_file
(note that the directories . and .. are not there.)
Failed Atempts
Just use ls options
The closest I've gotten is ls -alhvF --group-directories-first. It is almost there, but doesn't respect the desired order and keeps both . and ... I coulld strip those out a posteriori, but since the ordering is not correct, there is no point.
ls -lv namely the -v is nice as it sorts all the .files/dirs up alphabetical.
ls -l --goups-directories-first is also cool, does what is expected. To bad I can't make it 'act before' the -v.
Divide and Conquer
I though of splitting up the problem into two: I could first list the hidden files and then the not hidden: list_hidden; list_non_hiden. Then for simplicity of usage I could create an alias or function to call them in proper order.
The non-hidden is quite trivial! But listing solely the hidden files is becoming a bit more troublesome. I tried something like ls -ld .!(|.), but this has the drawback of using -d - so it cannot be used to list some other directory. At least not without having the full path of the file there...
Thanks!
The ls utility does not support what you want. So implement it yourself. List the files, then sort them, then ls them, yourself. A script that uses zero-terminated stream and GNU coreutils and findutils could look like the following:
{
printf "%s\0" . ..;
cmd=(
find "${1:-.}" -mindepth 1 -maxdepth 1 '('
-name '.*' '('
-type d -printf "1 %p\0"
')' -o
-printf "2 %p\0"
')' -o '('
'!' -name '.*' '('
-type d -printf "3 %p\0"
')' -o
-printf "4 %p\0"
')'
)
"${cmd[#]}" |
sort -z |
cut -z -d' ' -f2-;
} | xargs -0 ls -ald
You can patch some open-source ls utility with your own behavior - it would be nice and I am in favor of implementing it inside GNU coreutils ls as yet another option like --sort-hidden-directories-first to sort them in front of hidden files.
You can also write your own ls utility in C (or you could reimplement ls in shell, but I suspect It would be harder then just writing it in C).
Because I liked the idea for a long time and wanted to have hidden files sorted before anything else, I created this l utility that uses the method described above.
I’m working on requirement where I need to read first line from latest file under a directory. In a directory I can have multiple files but I want to read first line of latest file out all files which are having PPP in their file name.
I know how to read first line of file and write into a file
head -n 1 jsonPPPvp.txt > output.txt
But how can I pick latest file ( as per the time stamp) out of all files in a directory which are having PPP in it..?
Any suggestions please...!
I’ve written a command
Using find with -print0 and xargs -0 in a command substitution
Your optimal solution, though still requiring 4 subshells, will protect against all caveats in filenames by having find output nul-terminated filenames that can be used in conjunction with xargs -0 to form a nul-terminated list of filenames to be passed to ls for sorting in reverse selecting the last file with tail -n1 and the first line in that file with head -n1.
Using the -maxdepth 1 option to find limits the search to the current directory and prevent recursing into subdirectories (remove it if you want to search the entire directory tree below the current directory), e.g.
head -n1 $(find . -maxdepth 1 -type f -name "*PPP*" -print0 |
xargs -0 ls -rt |
tail -n 1)
In addition to working with nul-terminated filenames, it will benefit from letting xargs form the list to sort rather than looping to find the newest.
It is not maybe the best solution but it works (by latest file, I have considered the file modified with the most recent timestamp ):
ls -ltra
total 32
drwxr-xr-x 3 allanrobert primarygroup 4096 Feb 15 17:37 ..
drwxr-xr-x 2 allanrobert primarygroup 4096 Feb 15 17:37 .
-rw-r--r-- 1 allanrobert primarygroup 6 Feb 15 17:40 file2PPP2
-rw-r--r-- 1 allanrobert primarygroup 6 Feb 15 17:40 other
-rw-r--r-- 1 allanrobert primarygroup 6 Feb 15 17:40 file3PPP3
-rw-r--r-- 1 allanrobert primarygroup 6 Feb 15 17:40 other2
-rw-r--r-- 1 allanrobert primarygroup 6 Feb 15 17:40 other1
-rw-r--r-- 1 allanrobert primarygroup 6 Feb 15 17:40 file1PPP
file content:
cat file1PPP
a
b
c
Command:
find . -type f -maxdepth 1 -name '*PPP*' -printf '%T+ %p\n' | sort -r | head -1 | cut -d' ' -f2 | xargs head -1
a
Beware of spaces in filenames!
temp = `ls -Art | head -n 1 `
head -1 $temp
head -n 1 $(find ./ -name "*PPP*" -type f | xargs ls -rt1 | tail -n 1)
The drawback of the command above is that you must have a *PPP* file in your directory, otherwise the command produces wrong result.
You can also try this:
ls -tr | grep "PPP" | tail -n 1 | xargs head -n 1
If I ls -l in a directory and get:
-rwxr-x--- 1 user1 admin 0 8 Aug 2012 file.txt
-rwxr-x--- 1 user1 admin 1733480 26 Jul 2012 Archive.pax.gz
drwxr-x---# 7 user1 admin 238 31 Jul 2012 Mac Shots
-rwxr-x---# 1 user3 admin 598445 31 Jul 2012 Mac Shots.zip
-rwxr-x---# 1 user1 admin 380 6 Jul 2012 an.sh
-rwxr-x--- 1 user2 admin 14 30 Jun 2012 analystName.txt
-rwxr-x--- 1 user1 admin 36 8 Aug 2012 apple.txt
drwxr-x---# 7 user1 admin 238 31 Jul 2012 iPad Shots
-rwxr-x---# 1 user1 admin 7372367 31 Jul 2012 iPad Shots.zip
-rwxr-x--- 1 user2 admin 109 30 Jun 2012 test.txt
drwxr-x--- 3 user1 admin 102 26 Jul 2012 usr
but want to list only the files owned by "user1" which were modified in "Aug" to get
-rwxr-x--- 1 user1 admin 0 8 Aug 2012 file.txt
-rwxr-x--- 1 user1 admin 36 8 Aug 2012 apple.txt
What is the best method?
Parsing ls output is never a good and reliable solution. ls is a tool for interactively looking at file information. Its output is formatted for humans and will cause bugs in scripts. Use globs or find instead. Understand why: http://mywiki.wooledge.org/ParsingLs
Instead, you can try :
find . -type f -user 'user1' -maxdepth 1
or
find . -type f -printf '%u %f\n' -maxdepth 1 # if you want to show the username
or
stat -c '%U %f' * | cut -d" " -f2-
See
man find
man stat
Or you can be more explicit, since Michael's grep would also find a file owned by user1 namedd 'August iPad Shots' no matter when it was modified:
ls -l | awk '($3=="user1" && $7=="Aug")'
I think the safest way to do it is like this :
touch --date "2012-08-01" /tmp/start
touch --date "2012-09-01" /tmp/stop
find . -maxdepth 1 -type f -user user1 -newer /tmp/start -not -newer /tmp/stop -print0 | xargs -0 ls -l {}
rm /tmp/start /tmp/stop
Or as a one liner
touch --date "2012-08-01" /tmp/start; touch --date "2012-09-01" /tmp/stop; find . -maxdepth 1 -type f -user user1 -newer /tmp/start -not -newer /tmp/stop -print0 | xargs -0 ls -l {}; rm /tmp/start /tmp/stop
Advantages:
You don't parse ls
It works for filenames with Aug in them
Disadvantages
It is a bit long
Explanation:
-maxdepth 1: restricts the results to the current directory
-type f: restricts the results to files
-user user1: resttrings the results to files that belong to user1
-newer /tmp/start: restring the results to files newer than /tmp/start, which was created with the desired date
-not -newer /tmp/stop: restring the results to files not newer than /tmp/stop, which was created with the desired date
-print0: so it can handle filenames with newlines in their name!
How about ls -l | grep user1 | grep Aug?
Or you can combine the regexp: ls -l | grep 'user1.*Aug'
I use a find command to find some kinds of files in bash. Everything goes fine unlness the result that is shown to me just contains the file name but not the (last modification) date of file. I tried to pipe it into ls or ls -ltr but it just does not show the filedate column in result, also I tried this:
ls -ltr | find . -ctime 1
but actually I didn't work.
Can you please guide me how can I view the filedate of files returned by a find command?
You need either xargs or -exec for this:
find . -ctime 1 -exec ls -l {} \;
find . -ctime 1 | xargs ls -l
(The first executes ls on every found file individually, the second bunches them up into one ore more big ls invocations, so that they may be formatted slightly better.)
If all you want is to display an ls like output you can use the -ls option of find:
$ find . -name resolv.conf -ls
1048592 8 -rw-r--r-- 1 root root 126 Dec 9 10:12 ./resolv.conf
If you want only the timestamp you'll need to look at the -printf option
$ find . -name resolv.conf -printf "%a\n"
Mon May 21 09:15:24 2012
find . -ctime 1 -printf '%t\t%p\n'
prints the datetime and file path, separated by a ␉ character.