Shell code to print file names and their sizes - bash

I need to make a shell command that lists all file names and their sizes in a directory. I wrote this:
ls -l | awk ' {print $9, $5} '
the problem is that with $9 it only prints the first word of the name of the file.
Any tips to make it print the whole name?

Instead of parsing ls, use find:
find . -type f -printf "%s\t%f\n"
The %f directive prints the filename with leading directories removed. %s produces the file size in bytes.
For restricting the listing to the current directory, use -maxdepth:
find . -maxdepth 1 -type f -printf "%s\t%f\n"
You could also use stat:
stat --printf "%s\t%n\n" *

Related

How to print out subfolder ksh?

In the main folder, it contains a,b and c sub folder. I want to get every sub folder to be printed one by one..
for d in ${ls -R main}
do
printf "$d"
done
I would like it to print
a
b
c
so that I can use these subfolder later to check permission....
If You don't have to use only ksh You can do this with find like:
find /where/to/search/directories -type d -print
(-type d ensures that only directories will get find)
Or if You don't have find You can do it like:
ls -Rdl /path/to/search/directories/* | awk '/^d/ {print $9}'
awk parses ls -l output to filter out only directories and print the last field in the table.

Counting number of occurrences in several files

I want to check the number of occurrences of, let's say, the character '[', recursively in all the files of a directory that have the same extension, e.g. *.c. I am working with the SO Solaris in Unix.
I tried some solutions that are given in other posts, and the only one that works is this one, since with this OS I cannot use the command grep -o:
sed 's/[^x]//g' filename | tr -d '012' | wc -c
Where x is the occurrence I want to count. This one works but it's not recursive, is there any way to make it recursive?
You can get a recursive listing from find and execute commands with its -exec argument.
I'd suggest like:
find . -name '*.c' -exec cat {} \; | tr -c -d ']' | wc -c
The -c argument to tr means to use the opposite of the string supplied -- i.e. in this case, match everything but ].
The . in the find command means to search in the current directory, but you can supply any other directory name there as well.
I hope you have nawk installed. Then you can just:
nawk '{a+=gsub(/\]/,"x")}END{print a}' /path/*
You can write a snippet code itself. I suggest you to run the following:
awk '{for (i=1;i<=NF;i++) if ($i=="[") n++} END{print n}' *.c
This will search for "[" in all files in the present directory and print the number of occurrences.

How to print specific line of a group of files in defferent directories

I'm going to print specific line of a list of files which are in different sub directories. Say we have a main folder and t001 to t010 sub folders. I have a data.text in each one.
If all files were in a single directory we could simply have from here:
awk 'FNR==3' Files*
but here files are in sub directories. Do you have any idea?
Edit:
I think we can type:
awk 'FNR==3' ./t*/data.txt
Here I can't locate the file that has the data I was looking for. When I use :
grep -r -A 1 "string" *
I can see what I'm looking for in line after the string and also find the directory, but here I just need the line below the string.
find . -name "data.txt" -exec awk 'FNR==3' '{}' \;
See how to run find -exec
Edit
If you also need to print the filename as in the grep output then you can do it with FILENAME like so
find . -name "data.txt" -exec awk 'FNR==3 {print FILENAME ": " $0}' '{}' \;
or
awk 'FNR==3 {print FILENAME ": " $0}' ./t*/data.txt
Look for FILENAME in man awk for more information.

Using awk to read and create files in all subdirectories

I am trying to parse all files named "README" in all subdirectories (and sub-subdirectories) under my specified directory, and create a new file containing the parsed output in the same directory where each "README" file was found.
#!/bin/bash
FILES=$(find myDirectory -type f -name 'README')
for f in $FILES
do
#this is fine
echo "parsing $f"
#this is not fine
awk -F, 'BEGIN {print "header"};
{print $2;}
END {print "footer";}' $f > outputfile
done
The output file is only being created in my working directory. What I would like this to do is to perhaps redirect the output files into the subdirectories where their corresponding README's were found. Is there a better way than this?
If it helps, README format:
something,something2,something3
nothing1,nothing2,nothing3
Given that you want the output file created in the directory where the README was found, the simplest way is to use the POSIX standard dirname
command:
#!/bin/bash
FILES=$(find myDirectory -type f -name 'README')
for f in $FILES
do
outputfile="$(dirname "$f")/outputfile"
echo "parsing $f into $outputfile"
awk -F, 'BEGIN {print "header"}
{print $2}
END {print "footer"}' "$f" > "$outputfile"
done
This code is not safe if there are spaces or newlines in the directories, but assuming you stick with the portable file name character set (letters, digits, dot, dash and underscore), there'll be no major problems. (It wasn't safe before I made any changes; it still isn't safe. It isn't safe because you used FILES=$(find …) and while you do that, it is pretty much guaranteed to remain unsafe for names with blanks, tabs, newlines in them. There are ways to fix that, but they involve more major surgery.)
If you want, you can study the Bash parameter expansion mechanisms to see how to do it without using dirname.

extract columns with Bash or awk

I have a folder with 1000 text files. I would like to extract fourth and fifth columns from each file and save it to an another folder with the same filenames. How can I do this with awk or Bash?
Since you haven't specified about the field separator, I am assuming as the default(space) field separator.
awk '{print $4,$5>"/tmp/another_directory/"FILENAME}' *
With GNU find and GNU sed, assuming space separated columns and the files to process are in the current directory:
mkdir tmp/
find . -maxdepth 1 -type f -print0 |
xargs -0 -l /bin/sh -c 'sed -r "s/([^ ] *){3}([^ ]) *([^ ]*).*/\2 \3/" "$1" > "tmp/$1"' ''
Note the last pair of single quotes are important, they're a placeholders so the filename gets passed correctly to sh. The processed files are saved to tmp/ in the current directory.

Resources