bash - padding find results - bash

I'm running the following command to get a directory listing:
find ./../ \
-type f -newer ./lastsearchstamp -path . -prune -name '*.txt' -o -name '*.log' \
| awk -F/ '{print $NF " - " $FILENAME}'
Is there some way I can format the output in a 2 column left indented layout so that the output looks legible?
The command above always adds a constant spacing between the filename and the path.
Expected output:
abc.txt /root/somefolder/someotherfolder/
helloworld.txt /root/folder/someotherfolder/
a.sh /root/folder/someotherfolder/scripts

I nice tool for this kind of thing is column -t. You just add the command on to the end of the pipeline:
find ... | awk -F/ '{print $NF " - " $FILENAME}' | column -t

Related

Passing awk results to command after pipe

I'm trying to pass what would be the awk outputs of print $1 and print $2 to setfattr after a pipe. The value of the extended attribute is an MD5 hash which is calculated from input files from the output of a find command. This is what I have so far:
find /path/to/dir -type f \
-regextype posix-extended \
-not -iregex '.*\.(jpg|docx|psd|jpeg|png|html|bmp|gif|txt|pdf|mp3|bts|srt)' \
| parallel -j 64 md5sum | awk '{system("setfattr -n user.digest.md5 -v " $1 $2)}'
Having awk '{print $1}' and $2 after the last pipe returns the hash and file path respectively just fine, I'm just not sure how to get those values into setfattr. setfattr just throws a generic usage error when that command is run. Is this just a syntax issue or am I going about this totally wrong?
Try piping the output of the parallel command into a while loop:
find /path/to/dir -type f \
-regextype posix-extended \
-not -iregex '.*\.(jpg|docx|psd|jpeg|png|html|bmp|gif|txt|pdf|mp3|bts|srt)' |
parallel -j 64 md5sum |
while read hash file; do
setfattr -n user.digest.md5 -v ${hash} ${file}
done

Find the file path of a specific file inside a zipped folder

I'm struggling with my script. I want to find the full file path of a specific file, just like this example:
/path/folder_06may2017.zip/file_B.txt
I hope you can help me solving this problem. It will be really useful.
Directory and file samples
- Folder_01may2017.zip
+ file_A.txt
+ file_B.txt
- Folder_06may2017.zip
+ file_A.txt
+ file_B.txt
I have used this commands with no success at all:
1st attempt:
find "/path/folder/" -name "*06may2017*" -print -exec unzip -l {} \; | grep -i 'file_B'
1st Output:
182118 2017-05-06 11:20 file_B.txt
2nd attempt:
find "/path/folder/" -name "*06may2017*" -print -exec unzip -l {} \; | grep -i 'file_B'| awk '{ print $4 }' ${PWD}
2nd output:
awk: warning: command line argument '/path/folder' is a directory: skipped
3rd attempt:
find "/path/folder" -name "*06may2017*" -exec grep -l "file_B" /dev/null '{}' \;
3rd output
/path/folder/Folder_06may2017.zip
What about:
$ find "/path/folder" -name "*06may2017*" -exec unzip -l {} \; | awk '$1 ~ /Archive/{zipname = $2}; $4 ~ /file_B/ {printf "%s/%s\n", zipname, $4}'

Bash script to delete watched videos

I would like to create a bash script to check video files in a directory, and delete those, that are already watched.
I was thinking about using stat -c %w and stat -c %x and compare the birth and the last access of the video.
I have used stat -c %w to determine the date of the file creation, but I am unsure of stat -c %x. When is the access time updated? Will it really show the last time the video was opened? Is there any other scenarios that could change the access time?
Another issue is files that are in a directory and not "naked" in the work-directory. How should I handle those?
Do you have maybe a better solution?
find is using fstat system call as well.
-printf option can be used to display the modification time in seconds since EPOCH (%T#) and access time in seconds since EPOCH (%A#) and filename of each files found.
Naturally, awk can be used to compare the values and prints only filenames with different times.
Give this a try:
find . -type f -printf "%T# %A# %p\n" | awk '{if (substr($0,1,21)!=substr($0,23,21)) { print substr($0,45); }}' | xargs -I xxxx rm 'xxxx'
Maybe it should be tested first with printf:
find . -type f -printf "%T# %A# %p\n" | awk '{if (substr($0,1,21)!=substr($0,23,21)) { print substr($0,45); }}' | xargs -I xxxx printf "%s\n" 'xxxx'
The test of the version with printf:
$ touch foo bar
$ ls
bar foo
$ find . -type f -printf "%T# %A# %p\n" | awk '{if (substr($0,1,21)!=substr($0,23,21)) { print substr($0,45); }}' | xargs -I xxxx printf "%s\n" 'xxxx'
$ cat foo
$ find . -type f -printf "%T# %A# %p\n" | awk '{if (substr($0,1,21)!=substr($0,23,21)) { print substr($0,45); }}' | xargs -I xxxx printf "%s\n" 'xxxx'
./foo
Note: this one-liner command is working with filenames that do not contain special chars: \n " ' etc.

Using awk to print ALL spaces within filenames which have a varied number of spaces

I'm executing the following using bash and awk to get the potentially space-full filename, colon, file size. (Column 5 contains the space delimited size, and 9 to EOL the file name):
src="Desktop"
echo "Constructing $src files list. `date`"
cat /dev/null > "$src"Files.txt
find -s ~/"$src" -type f -exec ls -l {} \; |
awk '{for(i=9;i<=NF;i++) {printf("%s", $i " ")} print ":" $5}' |
grep -v ".DS_Store" | grep -v "Icon\r" |
while read line ; do filespacesize=`basename "$line"`; filesize=`echo "$filespacesize" |
sed -e 's/ :/:/1'`
path=`dirname "$line"`; echo "$filesize:$path" >> "$src"Files.txt ;
done
And it works fine, BUT…
If a filename has > 1 space between parts, I only get 1 space between filename parts, and the colon, followed by the filesize.
How can I get the full filename, :, and then the file size?
It seems you want the following (provided your find handles the printf option with the %f, %s and %h modifiers):
src=Desktop
echo "Constructing $src files list. $(date)"
find ~/"$src" -type f -printf '%f:%s:%h\n' > "$src"Files.txt
Much shorter and much more efficient than your method!
This will not discard the .DS_STORE and Icon\r things… but I'm not really sure what you really want to discard. If you want to discard the .DS_STORE directory altogether:
find ~/"$src" -name '.DS_STORE' -type d -prune -o -type f -printf '%f:%s:%h\n' > "$src"Files.txt
#guido seems to have guessed what you mean by grep -v "Icon\r": ignore files ending with Icon; if this his guess is right, then this will do:
find ~/"$src" -name '.DS_STORE' -type d -prune -o ! -name '*Icon' -type f -printf '%f:%s:%h\n' > "$src"Files.txt

How to remove files starting with #! or ending with .sh in the name

I am new to shell programming. I want to move any executable file, any file starting with shebang(#!), and any file whose name ends with .sh from a directory to /tmp/backup and log the names of the files moved.
This is what I have done till now
Searching for files with #^
grep -ircl --exclude=*.{png,jpg,gif,html,jar} "^#" /home
Finding executables
find . -type f -perm +111 or find . -type f -perm -u+x
Now I am struggling how to club these two commands get a final output which I can pass to perform backup and remove from current directory
Thanks
Use the xargs command
"find command" | xargs "grep command"
You could put everything in a file, sort it, then process it with Awk:
# Select all files to move
grep -ircl --exclude=*.{png,jpg,gif,html,jar} '^#\!' /home > list.txt
find /home -type f \( -perm -u+x -o -name "*.sh" \) -print >> list.txt
# Feed them to Awk that will log and move the file
sort list.txt | uniq | awk -v LOGFILE="mylog.txt" '
{ print "Moving " $0 >> LOGFILE
"mv -v --backup \"" $0 "\" /tmp/backup" | getline
print >> LOGFILE }'
EDIT: you can make a formal script out of this skeleton, by adding some variables and some additional checks:
#!/bin/bash
LIST="$( mktemp || exit 1 )"
LOG="/tmp/mylog.txt"
SOURCE="/home"
TARGET="/tmp/backup"
mkdir -p "${TARGET}"
cd "${SOURCE}" || exit 1
# Select all files to move
grep -ircl --exclude=*.{png,jpg,gif,html,jar} '^#\!' "${SOURCE}" > "${LIST}"
find "${SOURCE}" -type f \( -perm -u+x -o -name "*.sh" \) -print >> "${LIST}"
# Feed them to Awk that will log and move the file
sort "${LIST}" | uniq | awk -v LOGFILE="${LOG}" -v TARGET="${TARGET}" '
{ print "Moving " $0 >> LOGFILE
"mv -v --backup \"" $0 "\" " TARGET | getline
print >> LOGFILE }'

Resources