What does ^ character mean in grep ^d? - unix

When I do ls -l | grep ^d it lists only directories in the current directory.
What I'd like to know is what does the character ^ in ^d mean?

The caret ^ and the dollar sign $ are meta-characters that respectively match the empty string at the beginning and end of a line.The grep is matching only lines that start with "d".

To complement the good answer by The New Idiot, I want to point out that this:
ls -l | grep ^d
Shows all directories in the current directory. That's because the ls -l adds a d in the beginning of the directories info.
The format of ls -l is like:
-rwxr-xr-x 1 user group 0 Jun 12 12:25 exec_file
-rw-rw-r-- 1 user group 0 Jun 12 12:25 normal_file
drwxr-xr-x 16 user group 4096 May 24 12:46 dir
^
|___ see the "d"
To make it more clear, you can ls -lF to include a / to the end of the directories info:
-rwxr-xr-x 1 user group 0 Jun 12 12:25 exec_file*
-rw-rw-r-- 1 user group 0 Jun 12 12:25 normal_file
drwxr-xr-x 16 user group 4096 May 24 12:46 dir/
So ls -lF | grep /$ will do the same as ls -l | grep ^d.

It has two meanings. One as 'The New Idiot' above pointed out. The other, equally useful, is within character class expression, where it means negation: grep -E '[^[:digit:]]' accepts any character except a digit. The^` must be the first character within [].

Related

How to find file size greater than 200 MB in unix from a directory and its sub directory

Even though I used this command I am still getting output lesser than the 200 MB as well.
Command used:
find . -type f -size +200M -exec ls -lh {} \;
Output example
-rw-r--r-- 1 dummy dummy 101K Jul 27 22:43 ./sub_dir1/sub_dir2_1/file_1
-rw-r--r-- 1 dummy dummy 158M Jul 27 22:44 ./sub_dir1/sub_dir2_1/file_2
-rw-r--r-- 1 dummy dummy 1.1G Jul 27 22:44 ./sub_dir1/sub_dir2_2/file_3
-rw-r--r-- 1 dummy dummy 11M Jul 27 22:45 ./sub_dir1/sub_dir2_2/file_4
I have figured it out.
In some of the unix versions, We can't directly use the size as it is for the find commands.
In this it occupying 512 bytes.
Hence (200000000/512) = 390625
Unix command perfected:
find . -type f -size +390625 -exec ls -lh {} \;
Now it is working as expected.

Rsync: Keep destination file unchanged if same checksum

Let's say we have following files:
~/Homepage $ ls -l harp_output/BingSiteAuth.xml harp_netlify/BingSiteAuth.xml
-rw-r--r-- 1 david david 81 14. Mai 07:58 harp_netlify/BingSiteAuth.xml
-rw-r--r-- 1 david david 81 14. Mai 08:10 harp_output/BingSiteAuth.xml
The content of both files is identical:
~/Homepage $ cmp harp_output/BingSiteAuth.xml harp_netlify/BingSiteAuth.xml; echo $?
0
Therefore, I want harp_netlify/BingSiteAuth.xml not to be changed due to the identical content. With following command, however, the timestamp of the file on the destination side gets updated:
~/Homepage $ rsync -cav --delete harp_output/ harp_netlify/
The result is this:
~/Homepage $ ls -l harp_output/BingSiteAuth.xml harp_netlify/BingSiteAuth.xml
-rw-r--r-- 1 david david 81 14. Mai 08:10 harp_netlify/BingSiteAuth.xml
-rw-r--r-- 1 david david 81 14. Mai 08:10 harp_output/BingSiteAuth.xml
But, I want to have this:
~/Homepage $ ls -l harp_output/BingSiteAuth.xml harp_netlify/BingSiteAuth.xml
-rw-r--r-- 1 david david 81 14. Mai 07:58 harp_netlify/BingSiteAuth.xml
-rw-r--r-- 1 david david 81 14. Mai 08:10 harp_output/BingSiteAuth.xml
But, if the checksum is differed rsync must update the timestamp.
The arguments you are passing to rsync are -cav; the problem you have is the "a" which expands to -rlptgoD as explained in the man page, leaving you with a final -crlptgoDv argument list passed to rsync.
The tricky part of that is the p, t, g, and o, which preserve the permissions (p), modification times (t) (which is what is causing the sync change in your current example), group (g), and owner (o). If I understand your question correctly, what you want is:
rsync -crlDv --delete harp_output/ harp_netlify/
In this we preserve the "c" and "v" from your current command, and using the "r" (for recursive sync"), the "l" to preserve symlinks, and the "D" to preserve devices and special files. If all you want is to sync recursively based on checksums, and you don't care about links or special files, then "r" is enough; ie:
rsync -crv --delete harp_output/ harp_netlify/

How to compare html files in unix

I have two folders with huge number of HTML files and I want to compare each file and how to get the diff of each file using shell script/unix commands.
Example:
Directory 1:
1.html
2.html
3.html
Directory 2:
1.html
2.html
3.html..
I want to compare 1.html in directory with 1.html in dir2, and 2.html with 2.html, and so on.
try this;
#!/bin/bash
for file in $1/*.html; do
fileName=$(basename "$file")
if [ ! -f $2/$fileName ]; then
echo $fileName " not found! in "$2
else
difLineCount=$(diff $file $2/$fileName | wc -l)
if [ $difLineCount -eq 0 ]; then
echo $file "is same " $2/$fileName;
else
echo $file "is not same " $2/$fileName "." $difLineCount "lines are different";
#diff $file $2/$fileName
fi
fi
done
for file in $2/*.html; do
fileName=$(basename "$file")
if [ ! -f $1/$fileName ]; then
echo $fileName " not found! in "$1
fi
done
Ex :
user#host:/tmp$ ./test.sh Directory_1 Directory_2
Directory_1/1.html is same Directory_2/1.html
Directory_1/2.html is same Directory_2/2.html
Directory_1/3.html is not same Directory_2/3.html . 4 lines are different
4.html not found! in Directory_2
5.html not found! in Directory_1
user#host:/tmp$ ls -alrt Directory_1/
total 20
-rw-rw-r-- 1 user user 6 Ağu 11 13:28 1.html
-rw-rw-r-- 1 user user 6 Ağu 11 13:28 2.html
-rw-rw-r-- 1 user user 6 Ağu 11 13:28 3.html
-rw-rw-r-- 1 user user 0 Ağu 11 13:41 4.html
drwxrwxr-x 2 user user 4096 Ağu 11 13:41 .
drwxrwxr-x 4 user user 4096 Ağu 11 13:48 ..
user#host:/tmp$ ls -alrt Directory_2/
total 20
-rw-rw-r-- 1 user user 7 Ağu 11 13:28 3.html
-rw-rw-r-- 1 user user 6 Ağu 11 13:28 2.html
-rw-rw-r-- 1 user user 6 Ağu 11 13:28 1.html
-rw-rw-r-- 1 user user 0 Ağu 11 13:44 5.html
drwxrwxr-x 2 user user 4096 Ağu 11 13:44 .
drwxrwxr-x 4 user user 4096 Ağu 11 13:48 ..
You can use comm command to compare sorted files. This might be the actual solution you are looking for.
Syntax: comm file1 file2
Compare sorted files FILE1 and FILE2 line-by-line.
With no options, comm produces three-column output. Column one contains lines unique to FILE1, column two contains lines unique to FILE2, and column three contains lines common to both files. Each of these columns can be suppressed individually with options.
Keep the comm command in a loop such that it compares all the files in your required directories.
If you want to compare files one by one manually:
You need to use diff command to display line-by-line difference between two files.
Syntax: diff path/FILE1 path/FILE2
You can use --changed-group-format and --unchanged-group-format options to filter required data.
Following three options can use to select the relevant group for each option:
'%<' get lines from FILE1
'%>' get lines from FILE2
'' (empty string) for removing lines from both files.
Example: diff --changed-group-format="%<" --unchanged-group-format="" file1 file2
You can get a clear-cut visual difference between two text files using the command sdiff:
Syntax: sdiff path/file1 path/file2
If you have vim editor installed
use: vim -d file1 file2

How to list the files greater than specific timestamp in its pattern in Unix?

Can you please how I can accomplish the below scenario in Unix Ksh command?
I have a job J1 which is completed by the time HH:MM. I would like to list all the files created by this job J1, The file has the timestamp in its pattern YYYYMMDDHHMMSS_?
where YYYYMMDD is the date, HHMMSS is the system timestamp. I want to list the files if the job's timestamp is less than the file time stamp as the job creates the files, the timestamp of the job would be greater than the file timestamp?
Regards
Ben
You can use something like this: (Assuming the files listed)
$ ls -la
total 44K
drwxr-xr-x 2 gp users 4.0K Oct 27 14:56 .
drwxr-xr-x 11 gp users 4.0K Oct 27 14:57 ..
-rw-r--r-- 1 gp users 0 Oct 23 14:45 logfile
-rw-r--r-- 1 gp users 137 Oct 27 15:09 t2t2
prw-r--r-- 1 gp users 0 Oct 23 12:34 testpipe
-rw-r--r-- 1 gp users 0 Oct 23 14:51 tmpfile
-rw-r--r-- 1 gp users 7 Oct 27 14:58 ttt
# Find newer files
$ find . -newer ttt -print
./t2t2
# Find files that are NOT newer
$ find . ! -newer ttt -print
.
./tmpfile
./testpipe
./logfile
./ttt
# You can eliminate the directories (all of them) from the output this way:
$ find . ! -newer ttt ! -type d -print
./tmpfile
./testpipe
./logfile
./ttt
# or this way
$ find . ! -newer ttt -type f -print
Note that the different forms of the "newer" option (like anewer, cnewer) will not compare the other files against the the same timestamp. You might have to do a few tests to see which version suits you better.
If you must use the timestamp in the file name, and the different options of "find", including "mmin" are not acceptable, then you will have to examine the embedded timestamp of each file name. I suggest checking into these commands:
# You have to escape the < of > signs you use.
$ expr "fabc" \< "cde"
0
$ expr "abc" \< "cde"
1
and this:
FILENAME="ABC_20141026101112.log" ; TIMESTAMP="`expr \"$FILENAME\" : \".*_20\([0-9]\{12\}\).*$\"`";echo $TIMESTAMP
So a "while read" loop, looking at all the file names and comparing their timestamps using the above "expr" compares should do the job. Ideally, I'd try to see if "find" can do the job because reading and examining each file will be slower. If you have thousands of files in that directory, then I would try some other solution. If you are interested in more options, let me know.

How to properly grep filenames only from ls -al

How do I tell grep to only print out lines if the "filename" matches when I'm piping through ls? I want it to ignore everything on each line until after the timestamp. There must be some easy way to do this on a single command.
As you can see, without it, if I searched for the file "rwx", it would return not only the line with rwx.c, but also the first three lines because of permissions. I was going to use AWK but I want it to display the whole last line if I search for "rwx".
Any ideas?
EDIT: Thanks for the hacks below. However, it would be great to have a more bug-free method. For example, if I had a file named "rob rob", I wouldn't be able to use the stated solutions.
drwxrwxr-x 2 rob rob 4096 2012-03-04 18:03 .
drwxrwxr-x 4 rob rob 4096 2012-03-04 12:38 ..
-rwxrwxr-x 1 rob rob 13783 2012-03-04 18:03 a.out
-rw-rw-r-- 1 rob rob 4294 2012-03-04 18:02 function1.c
-rw-rw-r-- 1 rob rob 273 2012-03-04 12:54 function1.c~
-rw-rw-r-- 1 rob rob 16 2012-03-04 18:02 rwx.c
-rw-rw-r-- 1 rob rob 16 2012-03-04 18:02 rob rob
The following will list only file name, and one file in each row.
$ ls -1
To include . files
$ ls -1a
Please note that the argument is number "1", not letter "l".
Why don't you use grep and match the file name following the timestamp?
grep -P "[0-9]{2}:[0-9]{2} $FILENAME(\.[a-zA-Z0-9]+)?$"
The [0-9]{2}:[0-9]{2} is for the time, the $FILENAME is where you'd put rob rob or rwx, and the trailing (\.[a-zA-Z0-9]+)? is to allow for an optional extension.
Edit: #JonathanLeffler below points out that when files are older than bout 6 months the time column gets replaced by a year - this is what happens on my computer anyhow. You could do ([0-9]{2}:[0-9]{2}|(19|20)[0-9]{2}) to allow time OR year, but you may be best of using awk (?).
[foo#bar ~/tmp]$ls -al
total 8
drwxrwxr-x 2 foo foo 4096 Mar 5 09:30 .
drwxr-xr-- 83 foo foo 4096 Mar 5 09:30 ..
-rw-rw-r-- 1 foo foo 0 Mar 5 09:30 foo foo
-rw-rw-r-- 1 foo foo 0 Mar 5 09:29 rwx.c
-rw-rw-r-- 1 foo foo 0 Mar 5 09:29 tmp
[foo#bar ~/tmp]$export filename='foo foo'
[foo#bar ~/tmp]$echo $filename
foo foo
[foo#bar ~/tmp]$ls -al | grep -P "[0-9]{2}:[0-9]{2} $filename(\.[a-zA-Z0-9]+)?$"
-rw-rw-r-- 1 cha66i cha66i 0 Mar 5 09:30 foo foo
(You could additionally extend to matching the whole line if you wanted:
^ # start of line
[d-]([r-][w-][x-]){3} + # permissions & space (note: is there a 't' or 's'
# sometimes where the 'd' can be??)
[0-9]+ # whatever that number is
[\w-]+ [\w-]+ + # user/group (are spaces allowed in these?)
[0-9]+ + # file size (modify for -h switch??)
(19|20)[0-9]{2}- # yyyy (modify if you want to allow <1900)
(1[012]|0[1-9])- # mm
(0[1-9]|[12][0-9]|3[012]) + # dd
([01][0-9]|2[0-3]):[0-6][0-9] +# HH:MM (24hr)
$filename(\.[a-zA-Z0-9]+)? # filename & optional extension
$ # end of line
. You get the point, tailor to your needs.)
Assuming that you aren't prepared to do:
ls -ld $(ls -a | grep rwx)
then you need to exploit the fact that there are 8 columns with space separation before the file name starts. Using egrep (or grep -E), you could do:
ls -al | egrep "^([^ ]+ +){8}.*rwx"
This looks for 'rwx' after the 8th column. If you want the name to start with rwx, omit the .*. If you want the name to end with rwx, add a $ at the end. Note that I used double quotes so you could interpolate a variable in place of the literal rwx.
This was tested on Mac OS X 10.7.3; the ls -l command consistently gives three columns for the date field:
-r--r--r-- 1 jleffler staff 6510 Mar 17 2003 README,v
-r--r--r-- 1 jleffler staff 26676 Mar 3 21:44 ccs.nmd
Your ls -l seems to be giving just two columns, so you'd need to change the {8} to {7} for your machine - and beware migrating between systems.
Well, if you're working with filenames that don't have spaces in them, you could do something like this:
grep 'rwx\S*$'
Aside frrm the fact that you can use pattern matching with ls, exaple ksh and bash,
which is probably what you should do, you can use the fact that filename occur in a
fixed position. awk (gawk, nawk or whaever you have) is a better choice for this.
If you have to use grep it smells like homework to me. Please tag it that way.
Assume the filename starting position is based on this output from ls -l in linux: 56
-rwxr-xr-x 1 Administrators None 2052 Feb 28 20:29 vote2012.txt
ls -l | awk ' substr($0,56) ~/your pattern even with spaces goes here/'
e.g.,
ls -l | awk ' substr($0,56) ~/^val/'
will find files starting with "val"
As a simple hack, just add a space before your filename so you don't match the beginning of the output:
ls -al | grep '\srwx'
Edit: OK, this is not as robust as it should be. Here's awk:
ls -l | awk ' $9 ~ /rwx/ { print $0 }'
This works for me, unlike ls -l & others as some folks pointed out. I like this because its really generic & gives me the base file name, which removes the path names before the file.
ls -1 /path_name |awk -F/ '{print $NF}'
Only one command you needed for this --
ls -al | gawk '{print $9}'
You can use this:
ls -p | grep -v /
this is super old, but i needed the answer and had a hard time finding it. i didn't really care about the one-liner part; i just needed it done. this is down and dirty and requires that you count the columns. i'm not looking for an upvote here, just leaving some options for future searcher-ers.
the helpful awk trick is here -- Using awk to print all columns from the nth to the last
if
YOUR_FILENAME="rob rob"
and
WHERE_FILENAMES_START=8
ls -al | while read x; do
y=$(echo "$x" | awk '{for(i=$WHERE_FILENAMES_START; i<=NF; ++i) printf $i""FS; print ""}')
[[ "$YOUR_FILENAME " = "$y" ]] && echo "$x"
done
if you save it as a bash script and swap out the vars with $2 and $1, throw the script in your usr bin... then you'll have your clean simple one-liner ;)
output will be:
> -rw-rw-r-- 1 rob rob 16 2012-03-04 18:02 rob rob
the question was for a one-liner so...
ls -al | while read x; do [[ "$YOUR_FILENAME " = "$(echo "$x" | awk '{for(i=WHERE_FILENAMES_START; i<=NF; ++i) printf $i""FS; print ""}')" ]] && echo "$x" ; done
(lol ;P)
on another note: mathematical.coffee your answer was rad. it didn't solve my version of this problem, so i didn't upvote, but i liked your regex breakdown :D

Resources