Modify ext4 file system to add custom attribute for files - linux-kernel

I'm not very experienced in Linux kernel so I don't have idea how to do this.
What I have to do is to modify ext4 file system to add custom attributes in files (e.g. to add original location when file was created). So, not to add custom attribute to a particular file, but to all files when they are being created, automatically.
Any idea, or some link for deeper investigation?
Thanks

You will need something like extended attributes 'attr':
$ man attr
...
OVERVIEW
Extended attributes implement the ability for a user to attach name:value pairs to objects within the XFS
filesystem.
...
Install the command if it is not present in your system:
$ sudo apt install attr
I've used it within an ext4 file system:
$ echo "testing attr command" > test.txt
$ setfattr -n user.new_attr -v "attribute value" test.txt
$ getfattr -n user.new_attr test.txt
# file: test.txt
user.new_attr="attribute value"
Now you just need to intercept the creation of a file. You can use incron, as explained in:
Executing a bash script upon file creation
For more information, you can take a look at their respective man pages.

Related

Bash: How to edit a file onto/into itself - without using a secondary file

Note: I am particularly looking for a coding hack, not for an alternative solution. I am aware that awk, sed etc. can do this inline edit just fine.
$ echo '1' > test
$ cat test > test
$ cat test
$
Is there a way, to somehow make the second command output the original contents (1 in this case)? Again, I am looking for a hack which will work without visibly having to use a secondary file (using a secondary file in the background is fine). Another question on this forum solely focused on alternative solutions which is not what I am looking for.
You can store the content in a shell variable rather than a file.
var=$(<test)
printf "%s\n" "$var" > test
Note that this might only work for text files, not binary files. If you need to deal with them you can use encoding/decoding commands in the pipeline.
You can't do it without storing the data somewhere. When you redirect output to a file, the shell truncates the file immediately. If you use a pipeline, the commands in the pipeline run concurrently with the shell, and it's unpredictable which will run first -- the shell truncating the file or the command that tries to read from it.
With thanks to the comment made by #Cyrus to the original question
$ sudo apt install moreutils
$ echo '1' > test
$ cat test | sponge test
$ cat test
1
It does require installing an extra package and pre-checking for the binary using something like where sponge to check if it is installed.
if you happen to use macos, if the file isn't too gargantuan, you can always follow these steps :
perform the edits
pipe it to the clipboard (or "pasteboard" in mac lingo)
paste it back to original file name
|
{... edits to file1 ...} | pbcopy; pbpaste > file1

Variable for a right-clicked item (say, a jpg) in a bash script?

I have a very simple bash script that I run often from the cli, but I've found it's frustrating to have to open a terminal, identify the right file, and run it and think the easiest way would be to run it as an option from a right-click. I am running Ubuntu 18.04 LTS.
The script is just erasing exif data, leaving the orientation tags, essentially this:
exiftool -all= -tagsfromfile # -Orientation file-*.jpg
Is there a way to have the script identify which image I'm right clicking on? I'm at a loss what to put in the file-*.jpg part which will be a variable for "whatever image I'm right-clicking on right now."
Tried searching for a good while on how to do this but am clearly either not using the right search terms or else this isn't done very often. Thank you in advance for any help!
if you want your script to run in file manager right-click menu you have to change your script and define file(s) as arguments. this happens simply by changing your file section with $1 to $n as the parameter(s).
as far as I know ubuntu uses nautilus as an file manager.
you can run nautilus-actions-config-tool either from your terminal or from dash and define your script a name and a command to run. you can follow this link for illustration learning :
ubuntu nautilus defile script in menu
for example :
#!/bin/bash
if [ "$1" != "" ]; then
echo "Positional parameter 1 contains value $1"
else
echo "Positional parameter 1 is empty"
fi
for all arguments :
#!/bin/bash
if [[ "$#" -gt 0 ]]; then
for arg in "$#"; do
echo $arg
done
fi
here is the image that shows the script worked
I know the question is a little older, but I can provide you with the solution.
You have to set up FileManager-actions, an extension for GNOME/Nautilus (but it also works for other file managers).
Setup filemanager-actions on Ubuntu 20.04
sudo apt update
sudo apt install filemanager-actions
Then run fma-config-tool and create a new action.
When creating an action, please ensure that:
[v] Display item in selection context menu
is flagged; otherwise, you will not see the context menu during the file selection.
Prepare the script you want to execute
Prepare a script that does what you need. Touch in /tmp, mv it in /usr/bin and give it execute permissions:
touch /tmp/your-script
# edit it with your editor
sudo mv /tmp/your-script /usr/bin/
sudo chmod +x /usr/bin/your-script
In your script, you can reference the filename using $1.
FILENAME=$1
echo $FILENAME
In the variable FILENAME you will find the selected file name.
Configure Nautilus-action command
To let nautilus pass the filename, insert the script path and the argument string in the' command' tab.
To fully answer your question, to let Nautilus pass the filename as a script argument, you have to specify %f.
At this point, quit the Nautilus instance and open it again:
nautilus -q
nautilus
Now, let's have a try! Right-click on a file and check out the result!
Appendix 1 - Filemanager-actions formats
%f A single file name, even if multiple files are selected.
%F A list of files. Each file is passed as a separate argument to the executable program.
%u A single URL. Local files may either be passed as file: URLs or as file path.
%U A list of URLs. Each URL is passed as a separate argument to the executable program.
%d Base directory
Here you can find a comprehensive list.
Appendix 2 - Sources
Check out my post blog in which I actually realize something similar: https://gabrieleserra.ml/blog/2021-08-14-filemanager-actions-ubuntu-20-04.html
Reference to all possible formats for FileManager-actions: https://askubuntu.com/a/783313/940068
Realize it in Ubuntu 18.04: https://askubuntu.com/a/77285/940068

Bash Mutt email with attachment error Can't stat : No such file or directory

So i,ve read some other posts and tried out the answers, but i still keep running into this problem so i wanted to post a question here and see if anyone else had any other ideas. Keeping in mind i am pretty new to bash so i am iffy on whats available currently for what i,m looking for.
I am trying to automate a process that creates a file then sends it to me. All the above is fine, until i try to automatically email myself the file.
I have this line of code for it
echo "report" | mutt -- "$USEREMAIL" -s "report" -a "my_scripts/cid_reports/trb345432.csv"
When it tries to run this command it throws an error like
Can't stat my_scripts/cid_reports/trb345432.csv: No such file or directory
my_scripts/cid_reports/trb345432.csv: unable to attach file.
Any ideas on how i can fix this? I thought mutt was good to handle this, I am going to play with the mail feature and see if i can get any success with that.
The system looks to be running
Mutt 1.4.2.2i (2006-07-14)
Copyright (C) 1996-2002 Michael R. Elkins and others.
Mutt comes with ABSOLUTELY NO WARRANTY; for details type `mutt -v
mutt -h
-a <file> [...] -- attach file(s) to the message
The list of files must be terminated with the "--" sequence, so,
echo "hello world" | mutt -s "title" -a /home/test.txt -- ***#**.com
You need to add "--".
SIMPLE ANSWER
export EMAIL="sender_mail#example.com" | mutt -e "set content_type=text/html" -s "Test Mail" -c "cc_recipient#example.com" -a /tmp/attachment.txt -- "recipient_mail#example.com" < /tmp/message.html
Please use the following syntax while attaching files with 'mutt'.
# mutt -a file -- user#domain
For example;
# mutt -a /tmp/test.txt -- john#abc.com
Relevant snippets from the man page of mutt is given below.
Raw
-a file [...]
Attach a file to your message using MIME. When attaching single or multiple files, separating filenames and recipient addresses with "--" is mandatory,
e.g. mutt -a image.jpg -- addr1 or mutt -a img.jpg *.png -- addr1 addr2. The -a option must be placed at the end of command line options.
Ref: https://access.redhat.com/solutions/43567
The no such file or directory in general means that the file cannot be found. Because you're using a relative path, it might be that you are in a different directory?
If you type cat my_scripts/cid_reports/trb345432.csv from the same directory as you run the script, is the file there?
Or otherwise. if you use an absolute path (usually '/home/'uid'/my_scripts/cid_reports/trb345432.csv` but your path may be duifferent), does the script find the file?
(or should this have been a comment in stead of an answer, eventhough it tries to guide through finding the error?)
From your comments to Ljm Dullaart's answer, you're actually storing the file path in a variable, then using it something like this:
FILE="~/my_scripts/cid_reports/file.csv"
echo "report" | mutt -- "$USEREMAIL" -s "report" -a "$FILE"
If that's what you're doing, the problem is that ~ is in double-quotes, and therefore doesn't get expanded to the actual path to your home directory. Thus, it's looking for a sub directory literally named "~" under the current working directory, and not finding it. In order for ~ to be expanded to the path to your home directory, leave it and the following / unquoted, like this:
file=~/"my_scripts/cid_reports/file.csv"
echo "report" | mutt -- "$useremail" -s "report" -a "$file"
Note that I've also switched the variable names to lowercase. This is a best practice to avoid conflicts with the various environment variables that have special meanings; the special ones are all caps, so if you use lower- or mixed-case, you'll never accidentally trip over them.

What is the difference between -p and -q options

We have decided to split our jmeter properties into 2 files. One contains more "environment" related variables and the other contains more application centric (stuffs that changes with version).
Everything seems to work fine when using "jmeter.sh -q file1 -q file2 -t test.jmx". However we found there was also a -p option. In which context should it be use (vs the -q?)
According to the documentation:
-p, --propfile {argument}
the jmeter property file to use
-q, --addprop {argument}
additional property file(s)
this is, using -p you overwrite jmeter.properties, using -q adds a custom properties file.

Need to patch using a string/variable

I am writing a script to automate the process of setting up a bunch of Mac's in a computer lab.
Each system is uniquely identified and I need a method of patching a plist file in several locations with the same string that will be read from the user in the script which is a bash script
The original string is always the same. The patching string is variable depending on the identity of the system the script is being run on. This string is read from the user at the start of the script for various other purposes and stored in $macnum.
Can anybody please provide me a simple solution that can be scripted to perform the task? Thanks.
You can use some unique identifier (e.g. {{MACHINE_ID}}) in the plist and use sed to replace it:
sed -i -e 's/{{MACHINE_ID}}/'"$macnum"/g filename
sed -i "s/plist-macnum-placeholder/$macnum/g' file ...
Where -i means edit the file "in-place" and /g says make the substitution multiple times per line and can be dropped if there is only one.
The sed-based approach strager and msw gave will work fine if the plist you're changing is in XML format, but if it's in Apple's binary format it'll probably corrupt the file format. You can use plutil to convert it to XML first:
plutil -convert xml1 filename
sed -i -e "s/placeholder/$macnum/g" filename
It shouldn't be necessary to convert it back to binary format afterward, as Apple's plist frameworks read the two formats interchangeably. Another approach would be to use PlistBuddy to edit the contents of the plist (although it'll require the script to know what entries to set to what values, rather than just replacing a placeholder):
/usr/libexec/PlistBuddy -c "set :oneentry 'value including $macnum where appropriate'" filename
/usr/libexec/PlistBuddy -c "set :anotherentry 'value including $macnum where appropriate'" filename
Finally, you can do the same thing with defaults, although it requires you specify the .plist file by full path, and leave the .plist off its name:
defaults write oneentry "value including $macnum where appropriate" /path/to/filename-without-plist
defaults write anotherentry "value including $macnum where appropriate" /path/to/filename-without-plist

Resources