Let's say I have a logrotate config file as below:
"/data/logs/*.log" {
daily
rotate 5
compress
missingok
notifempty
prerotate
echo "file name is: <file_name>"
endscript
}
In the prerotate I'd like to perform a command in which I need to know of the wildcard's value. For the sake of this question let's say my command is very simple and is just the echo of the wildcard value.
How can I do this without creating a separate config definition for each possible value of the wildcard? Is there a way to point to the wildcard's value?
To run prerotate for every file instead of just once for the whole group, you need to add the nosharedscripts option. The name of the file is then handed to the script as the first argument, so if you have a script like
#!/usr/bin/env bash
echo "$1"
then you should be able to use this:
"/data/logs/*.log" {
daily
rotate 5
compress
missingok
notifempty
nosharedscripts
prerotate
/path/to/your/script
endscript
}
Related
I am trying to run the following function
foo () {
sleep 1
echo "outside inotify"
(inotifywait . -e create |
while read path action file; do
echo "test"
sleep 1
done)
echo "end"
}
Until inotifywait it runs correctly; I see:
>> foo
outside inotify
Setting up watches.
Watches established.
However as soon as I create a file, I get
>>> fooo
outside inotify
Setting up watches.
Watches established.
test
foo:6: command not found: sleep
end
Any idea why? Plus do I need to spawn the subprocess ( ) around inotifywait? what are the benefits?
thank you.
Edit
I realized I am running on zsh
The read path is messing you up, because unlike POSIX-compliant shells -- which guarantee that only modification to variables with all-uppercase names can have unwanted side effects on the shell itself -- zsh also has special-cased behavior for several lower-case names, including path.
In particular, zsh presents path as an array corresponding to the values in PATH. Assigning a string to this array will overwrite your PATH as well.
I want to write a fish shell to change the speed of an audio file.
The shell name is speed, I can call it like this:
speed 1.mp3 0.7
Then I will get a new file [0.7x] 1.mp3 with changed speed.
But I have a problem with the destination file name:
speed
#!/usr/local/bin/fish
set source $argv[1]
set ratio $argv[2]
ffmpeg -i $source -filter:a "atempo=$ratio" "[{$ratio}x] $source"
It will output a new file [{0.7}x] 1.mp3, which contains unnecessary {}. But if I remove it as the "[$ratiox] $source", the $ratiox is not correct too.
How to fix it?
The simplest is to exit the quotes:
ffmpeg -i $source -filter:a "atempo=$ratio" "["$ratio"x] $source"
I use UNIX fairly infrequently so I apologize if this seems like an easy question. I am trying to loop through subdirectories and files, then generate an output from the specific files that the loop grabs, then pipe an output to a file in another directory whos name will be identifiable from the input file. SO far I have:
for file in /home/sub_directory1/samples/SSTC*/
do
samtools depth -r chr9:218026635-21994999 < $file > /home/sub_directory_2/level_2/${file}_out
done
I was hoping to generate an output from file_1_novoalign.bam in sub_directory1/samples/SSTC*/ and to send that output to /home/sub_directory_2/level_2/ as an output file called file_1_novoalign_out.bam however it doesn't work - it says 'bash: /home/sub_directory_2/level_2/file_1_novoalign.bam.out: No such file or directory'.
I would ideally like to be able to strip off the '_novoalign.bam' part of the outfile and replace with '_out.txt'. I'm sure this will be easy for a regular unix user but I have searched and can't find a quick answer and don't really have time to spend ages searching. Thanks in advance for any suggestions building on the code I have so far or any alternate suggestions are welcome.
p.s. I don't have permission to write files to the directory containing the input folders
Beneath an explanation for filenames without spaces, keeping it simple.
When you want files, not directories, you should end your for-loop with * and not */.
When you only want to process files ending with _novoalign.bam, you should tell this to unix.
The easiest way is using sed for replacing a part of the string with sed.
A dollar-sign is for the end of the string. The total script will be
OUTDIR=/home/sub_directory_2/level_2
for file in /home/sub_directory1/samples/SSTC/*_novoalign.bam; do
echo Debug: Inputfile including path: ${file}
OUTPUTFILE=$(basename $file | sed -e 's/_novoalign.bam$/_out.txt/')
echo Debug: Outputfile without path: ${OUTPUTFILE}
samtools depth -r chr9:218026635-21994999 < ${file} > ${OUTDIR}/${OUTPUTFILE}
done
Note 1:
You can use parameter expansion like file=${fullfile##*/} to get the filename without path, but you will forget the syntax in one hour.
Easier to remember are basename and dirname, but you still have to do some processing.
Note 2:
When your script first changes the directory to /home/sub_directory_2/level_2 you can skip the basename call.
When all the files in the dir are to be processed, you can use the asterisk.
When all files have at most one underscore, you can use cut.
You might want to add some error handling. When you want the STDERR from samtools in your outputfile, add 2>&1.
These will turn your script into
OUTDIR=/home/sub_directory_2/level_2
cd /home/sub_directory1/samples/SSTC
for file in *; do
echo Debug: Inputfile: ${file}
OUTPUTFILE="$(basename $file | cut -d_ -f1)_out.txt"
echo Debug: Outputfile: ${OUTPUTFILE}
samtools depth -r chr9:218026635-21994999 < ${file} > ${OUTDIR}/${OUTPUTFILE} 2>&1
done
I'm using the bourne shell in UNIX, and am running into the following problem:
#!/bin/sh
while read line
do
echo $line
if [ $x = "true" ]
then
echo "something"
read choice
echo $choice
else
echo "something"
fi
done <file.txt
The problem I have here is that UNIX will not wait for user input in the read command - it just plows on through instead of waiting for what the user types in. How can I make unix wait for user input?
It is because you are asking the program to read from the file file.txt:
done <file.txt
Also looks like you have a typo here:
if [ $x = "true" ]
^^
which should be "$line". Also note the ", without them your program will break if the word read from the file has a space in it.
The redirection of standard input by the <file.txt at the end of while ... done <file.txt affects the whole while loop, including the read choice as well as the read line. It's not just failing to stop - it's consuming a line of your input file too.
Here's one way to solve the problem...
You can save the original standard input by using the somewhat obscure (even by shell standards):
exec 3<&0
which opens file descriptor 3 to refer to the original file descriptor 0, which is the original standard input. (File descriptors 0, 1 and 2 are standard input, output and error respectively.) And then you can redirect just the input of read choice to come from file descriptor 3 by doing read choice <&3.
Complete working script (I wasn't sure where x was supposed to come from, so I just bodged it to make it work):
#!/bin/sh
x=true # to make the example work
exec 3<&0
while read line
do
echo $line
if [ $x = "true" ]
then
echo "something"
read choice <&3
else
echo "something"
fi
done <file.txt
I don't do much shell scripting, but i think 'read choice' should be 'read $choice'
Have a shell script that reads the files in a particular directory.
#!/bin/bash
for fspec in /exp/dira/test/ready/* ; do
done
I want to modify the unix shell script so that path is retreived from enviornmental variable.
export CUST_DATA=${_FX_DATA_}/test have set this variable in environment thru .profile
#!/bin/bash
READY_FILES= "$CUST_DATA/ready"
for fspec in $READY_FILES/* ; do
done
i tried the above but it's not working.
The space after the equal sign makes it mean something completely different.
#!/bin/bash
READY_FILES="$CUST_DATA/ready"
for fspec in "$READY_FILES"/* ; do
....
done
#!/bin/bash
. ~/.profile
READY_FILES="$CUST_DATA/ready"
for fspec in $READY_FILES/* ; do
...
done
add echo "<$CUST_DATA>" to your second script to make sure that variable is not set.